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.

388 lines
14 KiB

  1. using Microsoft.Azure.Cosmos;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace CDP
  8. {
  9. public class GroupsDB
  10. {
  11. private static Lazy<CosmosClient> lazyClient = new Lazy<CosmosClient>(InitializeCosmosClient);
  12. private static CosmosClient cosmosClient => lazyClient.Value;
  13. private static string DatabaseName = "CDP";
  14. private static string ContainerName = "Groups";
  15. private static CosmosClient InitializeCosmosClient()
  16. {
  17. // Perform any initialization here
  18. var uri = "https://cdplite.documents.azure.com:443/";
  19. var authKey = "VPbg8RpzyI3XwhC2o0dIUtYFs33ghxORCqZeNAyg8vg4HWUBjM41BUxP0qLFXEvFh6ewQY1uKv52ACDbsEN1AQ==";
  20. return new CosmosClient(uri, authKey);
  21. }
  22. public static async Task<List<GroupsRecord>> GetUserGroups(string AppKey, string UserId)
  23. {
  24. var results = new List<GroupsRecord>();
  25. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  26. // Fetch the metadata document for the customer ID
  27. var metadataDocumentId = GetMetaDocumentKey(AppKey, UserId);
  28. MetadataDocumentGroups metadataDocument = null;
  29. try
  30. {
  31. var metadataDocumentResponse =
  32. await container.ReadItemAsync<MetadataDocumentGroups>(metadataDocumentId, new PartitionKey(metadataDocumentId));
  33. metadataDocument = metadataDocumentResponse.Resource;
  34. }
  35. catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  36. {
  37. }
  38. catch (Exception e)
  39. {
  40. // Helpers.LogIt(e.Message);
  41. }
  42. if (metadataDocument == null)
  43. return results;
  44. // Determine the partition keys within the date range
  45. var partitionKeysInDocument = metadataDocument.PartitionKeys;
  46. // Fetch the audit records for each partition key within the date range
  47. foreach (var partitionKey in partitionKeysInDocument)
  48. {
  49. ItemResponse<GroupsDocument> response = await container.ReadItemAsync<GroupsDocument>(partitionKey, new PartitionKey(partitionKey));
  50. if (response == null)
  51. continue;
  52. GroupsDocument t = response.Resource;
  53. results.AddRange(t.Records);
  54. }
  55. return results;
  56. }
  57. public static async Task<bool> RemoveGroup(string appKey, string userId, string groupId)
  58. {
  59. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  60. // Fetch the metadata document for the customer ID
  61. var metadataDocumentId = GetMetaDocumentKey(appKey, userId);
  62. MetadataDocumentContact metadataDocument = null;
  63. try
  64. {
  65. var metadataDocumentResponse = await container.ReadItemAsync<MetadataDocumentContact>(metadataDocumentId, new PartitionKey(metadataDocumentId));
  66. metadataDocument = metadataDocumentResponse.Resource;
  67. }
  68. catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  69. {
  70. }
  71. catch (Exception e)
  72. {
  73. // Helpers.LogIt(e.Message);
  74. }
  75. if (metadataDocument == null)
  76. return false;
  77. // Determine the partition keys within the date range
  78. var partitionKeysInDocument = metadataDocument.PartitionKeys;
  79. // Fetch the audit records for each partition key within the date range
  80. foreach (var partitionKey in partitionKeysInDocument)
  81. {
  82. ItemResponse<GroupsDocument> response = await container.ReadItemAsync<GroupsDocument>(partitionKey, new PartitionKey(partitionKey));
  83. if (response == null)
  84. continue;
  85. GroupsDocument t = response.Resource;
  86. var originalCount = t.Records.Count;
  87. t.Records = t.Records.Where(item => item.id != groupId).ToList();
  88. var afterFilterCount = t.Records.Count;
  89. if (originalCount != afterFilterCount)
  90. {
  91. ItemResponse<GroupsDocument> updateResponse = await container.ReplaceItemAsync(
  92. item: t,
  93. id: t.id,
  94. partitionKey: new PartitionKey(partitionKey));
  95. return true;
  96. }
  97. }
  98. return false;
  99. }
  100. public static async Task<bool> AppendGroup(string appKey, string userId, String grpName, string grpDescription, List<ContactRecord> rec)
  101. {
  102. try
  103. {
  104. var metadataDocument = await GetMetadataDocument(appKey, userId);
  105. if (metadataDocument == null)
  106. return false;
  107. string dayKey = metadataDocument.GetLatestKey(appKey, userId);
  108. GroupsDocument al = await GetGroupDocument(dayKey);
  109. if (al == null)
  110. {
  111. al = new GroupsDocument();
  112. al.AppKey = appKey;
  113. al.UserId = userId;
  114. }
  115. GroupsRecord gr = new GroupsRecord(grpName, grpDescription, rec);
  116. al.Records.Add(gr);
  117. await UpdateGroupsDocument(al);
  118. return true;
  119. }
  120. catch (Exception e)
  121. {
  122. return false;
  123. }
  124. }
  125. public static async Task<bool> UpdateGroup(string appKey, string userId, string grpId, string grpName, string grpDescription, List<ContactRecord> contacts)
  126. {
  127. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  128. // Fetch the metadata document for the customer ID
  129. var metadataDocumentId = GetMetaDocumentKey(appKey, userId);
  130. MetadataDocumentContact metadataDocument = null;
  131. try
  132. {
  133. var metadataDocumentResponse = await container.ReadItemAsync<MetadataDocumentContact>(metadataDocumentId, new PartitionKey(metadataDocumentId));
  134. metadataDocument = metadataDocumentResponse.Resource;
  135. }
  136. catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  137. {
  138. }
  139. catch (Exception e)
  140. {
  141. // Helpers.LogIt(e.Message);
  142. }
  143. if (metadataDocument == null)
  144. return false;
  145. // Determine the partition keys within the date range
  146. var partitionKeysInDocument = metadataDocument.PartitionKeys;
  147. // Fetch the audit records for each partition key within the date range
  148. foreach (var partitionKey in partitionKeysInDocument)
  149. {
  150. ItemResponse<GroupsDocument> response = await container.ReadItemAsync<GroupsDocument>(partitionKey, new PartitionKey(partitionKey));
  151. if (response == null)
  152. continue;
  153. GroupsDocument t = response.Resource;
  154. bool groupFound = false;
  155. foreach (GroupsRecord gr in t.Records)
  156. {
  157. if (gr.id == grpId)
  158. {
  159. gr.Name = grpName != "" ? grpName : gr.Name;
  160. gr.Description = grpDescription != "" ? grpDescription : gr.Description;
  161. gr.Contacts = contacts;
  162. groupFound = true;
  163. break;
  164. }
  165. }
  166. if (groupFound)
  167. {
  168. ItemResponse<GroupsDocument> updateResponse = await container.ReplaceItemAsync(
  169. item: t,
  170. id: t.id,
  171. partitionKey: new PartitionKey(partitionKey));
  172. return true;
  173. }
  174. }
  175. return false;
  176. }
  177. public static async Task UpdateGroupsDocument(GroupsDocument al)
  178. {
  179. if (al.Records.Count == 0)
  180. return;
  181. List<GroupsDocument> lal = await SplitUserGroups(al);
  182. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  183. foreach (GroupsDocument ial in lal)
  184. {
  185. ItemResponse<GroupsDocument> r = await container.UpsertItemAsync(ial, new PartitionKey(ial.id));
  186. }
  187. await UpdateMetadata(container, lal);
  188. }
  189. static async Task UpdateMetadata(Container container, List<GroupsDocument> lal)
  190. {
  191. bool update = false;
  192. string pKey = GetMetaDocumentKey(lal[0].AppKey, lal[0].UserId);
  193. MetadataDocument md = null;
  194. try
  195. {
  196. ItemResponse<MetadataDocument> response =
  197. await container.ReadItemAsync<MetadataDocument>(pKey, new PartitionKey(pKey));
  198. md = response.Resource;
  199. }
  200. catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  201. {
  202. md = new MetadataDocument()
  203. {
  204. id = GetMetaDocumentKey(lal[0].AppKey, lal[0].UserId),
  205. PartitionKeys = new List<string>()
  206. };
  207. }
  208. catch (Exception e)
  209. {
  210. // Helpers.LogIt(e.Message);
  211. return;
  212. }
  213. if (md == null)
  214. {
  215. // Helpers.LogIt("Something ugly happened!");
  216. return;
  217. }
  218. foreach (GroupsDocument log in lal)
  219. {
  220. if (md.PartitionKeys.Contains(log.id))
  221. continue;
  222. md.PartitionKeys.Add(log.id);
  223. update = true;
  224. }
  225. if (update)
  226. {
  227. try
  228. {
  229. ItemResponse<MetadataDocument> r = await container.UpsertItemAsync(md, new PartitionKey(pKey));
  230. }
  231. catch (Exception e)
  232. {
  233. // Helpers.LogIt(e.Message);
  234. return;
  235. }
  236. }
  237. }
  238. static async Task<List<GroupsDocument>> SplitUserGroups(GroupsDocument al)
  239. {
  240. List<GroupsDocument> lal = new List<GroupsDocument>();
  241. var sortedRecords = al.Records.OrderBy(record => record.EventTime).ToList();
  242. var currentGroup = new List<GroupsRecord>();
  243. var currentGroupSize = 0;
  244. int MaxDocumentSizeInBytes = 2 * 1024 * 1024; // 2MB
  245. int index = al.Index; // start for index passed in
  246. foreach (var record in sortedRecords)
  247. {
  248. var recordSize = record.CalculateRecordSize();
  249. if (currentGroupSize + recordSize > MaxDocumentSizeInBytes)
  250. {
  251. GroupsDocument i = new GroupsDocument();
  252. i.Index = index++;
  253. i.Records = currentGroup;
  254. i.AppKey = al.AppKey;
  255. i.UserId = al.UserId;
  256. lal.Add(i);
  257. currentGroup = new List<GroupsRecord>();
  258. currentGroupSize = 0;
  259. }
  260. currentGroup.Add(record);
  261. currentGroupSize += recordSize;
  262. }
  263. if (currentGroup.Any())
  264. {
  265. GroupsDocument i = new GroupsDocument();
  266. i.Index = index++;
  267. i.Records = currentGroup;
  268. i.AppKey = al.AppKey;
  269. i.UserId = al.UserId;
  270. lal.Add(i);
  271. }
  272. return lal;
  273. }
  274. public static async Task<GroupsDocument> GetGroupDocument(string key)
  275. {
  276. try
  277. {
  278. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  279. ItemResponse<GroupsDocument> response = await container.ReadItemAsync<GroupsDocument>(key, new PartitionKey(key));
  280. if (response == null)
  281. return null;
  282. GroupsDocument t = response.Resource;
  283. return t;
  284. }
  285. catch (Exception e)
  286. {
  287. return null;
  288. }
  289. }
  290. static async Task<MetadataDocumentGroups> GetMetadataDocument(string appKey, string userId)
  291. {
  292. MetadataDocumentGroups md = null;
  293. string pKey = GetMetaDocumentKey(appKey, userId);
  294. string id = GetDocumentId(appKey, userId);
  295. PartitionKey partitionKey = new PartitionKeyBuilder()
  296. .Add(pKey)
  297. .Build();
  298. Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
  299. try
  300. {
  301. ItemResponse<MetadataDocumentGroups> response =
  302. await container.ReadItemAsync<MetadataDocumentGroups>(pKey, partitionKey);
  303. md = response.Resource;
  304. }
  305. catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  306. {
  307. md = new MetadataDocumentGroups()
  308. {
  309. id = id,
  310. PartitionKeys = new List<string>()
  311. };
  312. }
  313. catch (Exception e)
  314. {
  315. // Helpers.LogIt(e.Message);
  316. return null;
  317. }
  318. if (md == null)
  319. {
  320. // Helpers.LogIt("Something ugly happened!");
  321. return null;
  322. }
  323. return md;
  324. }
  325. static string GetMetaDocumentKey(string appKey, string userId)
  326. {
  327. return $"{appKey}-{userId}-meta";
  328. }
  329. static string GetDocumentId(string appKey, string userId)
  330. {
  331. return $"{appKey}-{userId}";
  332. }
  333. }
  334. }