Temporary repo to track my changes on LTS functions app porting
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

229 lines
8.9 KiB

  1. using Microsoft.AspNetCore.Http;
  2. using Microsoft.AspNetCore.Mvc;
  3. using Microsoft.Azure.Cosmos;
  4. using Microsoft.Azure.Functions.Worker;
  5. using Microsoft.Azure.Functions.Worker.Http;
  6. using Microsoft.Extensions.Logging;
  7. using Newtonsoft.Json;
  8. using System.Net;
  9. using FromBodyAttribute = Microsoft.Azure.Functions.Worker.Http.FromBodyAttribute;
  10. namespace CDP
  11. {
  12. public class FileRevision
  13. {
  14. private readonly ILogger<FileRevision> _logger;
  15. private static Lazy<CosmosClient> lazyClient = new Lazy<CosmosClient>(InitializeCosmosClient);
  16. private static CosmosClient cosmosClient => lazyClient.Value;
  17. private static string DatabaseName = "CDP";
  18. private static string ContainerName = "RevisionsContainer";
  19. public FileRevision(ILogger<FileRevision> logger)
  20. {
  21. _logger = logger;
  22. }
  23. private static CosmosClient InitializeCosmosClient()
  24. {
  25. // Perform any initialization here
  26. var uri = "https://cdplite.documents.azure.com:443/";
  27. var authKey = "VPbg8RpzyI3XwhC2o0dIUtYFs33ghxORCqZeNAyg8vg4HWUBjM41BUxP0qLFXEvFh6ewQY1uKv52ACDbsEN1AQ==";
  28. return new CosmosClient(uri, authKey);
  29. }
  30. public static async Task<RevisionEntry> GetFileRevisionInternal(string appKey, string fileId)
  31. {
  32. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  33. string id = Helpers.HashAndShortenText(appKey + fileId);
  34. PartitionKey key = new PartitionKeyBuilder().Add(appKey).Add(fileId).Build();
  35. var item = await container.ReadItemAsync<RevisionEntry>(id, key);
  36. return item.Resource;
  37. }
  38. static internal async Task<IActionResult> AddRevisionInternal(AddRevisionDocumentDto doc, ILogger _logger)
  39. {
  40. try
  41. {
  42. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  43. _logger.LogInformation("container id: ", container);
  44. RevisionDocument document = new RevisionDocument()
  45. {
  46. //AppKey = doc.AppKey,
  47. //FileId = doc.FileId,
  48. RevisionId = doc.RevisionId,
  49. EditedBy = doc.EditedBy,
  50. Comments = doc.Comments,
  51. RevisionDate = doc.RevisionDate
  52. };
  53. string id = Helpers.HashAndShortenText(doc.AppKey + doc.FileId);
  54. PartitionKey partitionKey = new PartitionKeyBuilder()
  55. .Add(doc.AppKey)
  56. .Add(doc.FileId)
  57. .Build();
  58. var res = await AddOrUpdateRevision(container, id, partitionKey, document, doc.AppKey, doc.FileId);
  59. return new OkObjectResult(res);
  60. }
  61. catch (Exception ex)
  62. {
  63. _logger.LogError(ex.ToString());
  64. return new StatusCodeResult(500);
  65. }
  66. }
  67. public async static Task<string> AddMailBodyRevision(RevisionDocument document, CompoundDocument compoundDocument, string AppKey, string FileId)
  68. {
  69. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  70. List<RevisionDocument> documents = new List<RevisionDocument> { document };
  71. RevisionEntry entry = new RevisionEntry
  72. {
  73. AppKey = AppKey,
  74. FileId = FileId,
  75. FileRevisions = documents,
  76. CompoundDocument = compoundDocument
  77. };
  78. ItemResponse<RevisionEntry> item = await container.CreateItemAsync<RevisionEntry>(entry);
  79. return item.Resource.id;
  80. }
  81. private async static Task<RevisionEntry> AddOrUpdateRevision(Container container, string id, PartitionKey partitionKey, RevisionDocument document, string appKey, string fileId)
  82. {
  83. try
  84. {
  85. ItemResponse<RevisionEntry> item = await container.ReadItemAsync<RevisionEntry>(id, partitionKey);
  86. RevisionEntry revisions = item.Resource;
  87. revisions.FileRevisions.Add(document);
  88. ItemRequestOptions requestOptions = new ItemRequestOptions
  89. {
  90. IfMatchEtag = item.ETag
  91. };
  92. var res = await container.UpsertItemAsync<RevisionEntry>(revisions, partitionKey);
  93. return res.Resource;
  94. }
  95. catch (CosmosException ex)
  96. {
  97. if (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  98. {
  99. List<RevisionDocument> revisions = new List<RevisionDocument>
  100. {
  101. document
  102. };
  103. RevisionEntry entry = new RevisionEntry()
  104. {
  105. AppKey = appKey,
  106. FileId = fileId,
  107. FileRevisions = revisions
  108. };
  109. ItemResponse<RevisionEntry> item = await container.CreateItemAsync<RevisionEntry>(entry);
  110. return item.Resource;
  111. }
  112. else if (ex.StatusCode == HttpStatusCode.PreconditionFailed)
  113. {
  114. return await AddOrUpdateRevision(container, id, partitionKey, document, appKey, fileId);
  115. }
  116. else
  117. {
  118. throw ex;
  119. }
  120. }
  121. }
  122. #region Versioning Functions
  123. [Function("AddRevisionDocument")]
  124. public async Task<IActionResult> AddRevisionDocument([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
  125. {
  126. _logger.LogInformation("C# HTTP trigger function processed a request for update revision");
  127. string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
  128. AddRevisionDocumentDto doc;
  129. try
  130. {
  131. doc = JsonConvert.DeserializeObject<AddRevisionDocumentDto>(requestBody);
  132. _logger.LogInformation(doc.RevisionId + doc.AppKey + doc.FileId);
  133. }
  134. catch (Exception ex)
  135. {
  136. _logger.LogError(ex.ToString());
  137. return new BadRequestObjectResult("Invalid request format");
  138. }
  139. return await AddRevisionInternal(doc, _logger);
  140. }
  141. [Function("GetFileRevisions")]
  142. public async Task<IActionResult> GetFileRevisions([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, [FromBody] GetRevisionsDto reqDto)
  143. {
  144. _logger.LogInformation("C# HTTP trigger function processed a request for update revision", JsonConvert.SerializeObject(reqDto));
  145. try
  146. {
  147. var item = await GetFileRevisionInternal(reqDto.AppKey, reqDto.FileId);
  148. if (item.CompoundDocument != null)
  149. {
  150. return new OkObjectResult(item);
  151. }
  152. List<RevisionDocument> revisions = item.FileRevisions;
  153. //_logger.LogInformation("docs: {0}", JsonConvert.SerializeObject(revisions));
  154. return new OkObjectResult(revisions);
  155. }
  156. catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
  157. {
  158. return new StatusCodeResult(404);
  159. }
  160. }
  161. #endregion
  162. }
  163. public class GetRevisionsDto
  164. {
  165. public required string AppKey { get; set; }
  166. public required string FileId { get; set; }
  167. }
  168. public class AddRevisionDocumentDto
  169. {
  170. public required string AppKey { get; set; }
  171. public required string FileId { get; set; }
  172. public required string RevisionId { get; set; }
  173. public required string EditedBy { get; set; }
  174. public required DateTime RevisionDate { get; set; }
  175. public required string Comments { get; set; }
  176. }
  177. public class RevisionDocument
  178. {
  179. public required string RevisionId { get; set; }
  180. public required string EditedBy { get; set; }
  181. public required DateTime RevisionDate { get; set; }
  182. public required string Comments { get; set; }
  183. }
  184. public class RevisionEntry
  185. {
  186. public string id
  187. {
  188. get
  189. {
  190. string s = Helpers.HashAndShortenText(AppKey + FileId);
  191. return s.Replace('/', '-');
  192. }
  193. }
  194. public required string AppKey { get; set; }
  195. public required string FileId { get; set; }
  196. public List<RevisionDocument> FileRevisions { get; set; }
  197. public CompoundDocument? CompoundDocument { get; set; }
  198. }
  199. public class CompoundDocument
  200. {
  201. public required string Id { get; set; }
  202. public required string AppKey { get; set; }
  203. public required string Contents { get; set; } //can be MailRecord below
  204. public required string DocumentType { get; set; }
  205. }
  206. }