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.
327 lines
12 KiB
327 lines
12 KiB
using Microsoft.Azure.Cosmos;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace CDP
|
|
{
|
|
public class ContactsDB
|
|
{
|
|
private static Lazy<CosmosClient> lazyClient = new Lazy<CosmosClient>(InitializeCosmosClient);
|
|
private static CosmosClient cosmosClient => lazyClient.Value;
|
|
private static string DatabaseName = "CDP";
|
|
private static string ContainerName = "Contacts";
|
|
|
|
private static CosmosClient InitializeCosmosClient()
|
|
{
|
|
// Perform any initialization here
|
|
var uri = "https://cdplite.documents.azure.com:443/";
|
|
var authKey = "VPbg8RpzyI3XwhC2o0dIUtYFs33ghxORCqZeNAyg8vg4HWUBjM41BUxP0qLFXEvFh6ewQY1uKv52ACDbsEN1AQ==";
|
|
|
|
return new CosmosClient(uri, authKey);
|
|
}
|
|
|
|
public static async Task<List<ContactRecord>> GetUserContacts(string AppKey, string UserId)
|
|
{
|
|
var results = new List<ContactRecord>();
|
|
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
|
|
|
|
// Fetch the metadata document for the customer ID
|
|
var metadataDocumentId = GetMetaDocumentKey(AppKey, UserId);
|
|
MetadataDocumentContact metadataDocument = null;
|
|
try
|
|
{
|
|
var metadataDocumentResponse =
|
|
await container.ReadItemAsync<MetadataDocumentContact>(metadataDocumentId, new PartitionKey(metadataDocumentId));
|
|
metadataDocument = metadataDocumentResponse.Resource;
|
|
}
|
|
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
{
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Helpers.LogIt(e.Message);
|
|
}
|
|
|
|
if (metadataDocument == null)
|
|
return results;
|
|
|
|
// Determine the partition keys within the date range
|
|
var partitionKeysInDocument = metadataDocument.PartitionKeys;
|
|
// Fetch the audit records for each partition key within the date range
|
|
foreach (var partitionKey in partitionKeysInDocument)
|
|
{
|
|
|
|
ItemResponse<ContactsDocument> response = await container.ReadItemAsync<ContactsDocument>(partitionKey, new PartitionKey(partitionKey));
|
|
if (response == null)
|
|
continue;
|
|
|
|
ContactsDocument t = response.Resource;
|
|
results.AddRange(t.Records);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
public static async Task<bool> AppendRecord(string appKey, string userId, ContactRecord rec)
|
|
{
|
|
try
|
|
{
|
|
var metadataDocument = await GetMetadataDocument(appKey, userId);
|
|
if (metadataDocument == null)
|
|
return false;
|
|
|
|
string dayKey = metadataDocument.GetLatestKey(appKey, userId);
|
|
ContactsDocument al = await GetContactDocument(dayKey);
|
|
if (al == null)
|
|
{
|
|
al = new ContactsDocument();
|
|
al.AppKey = appKey;
|
|
al.UserId = userId;
|
|
}
|
|
al.Records.Add(rec);
|
|
await UpdateContactsDocument(al);
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static async Task<bool> RemoveRecord(string appKey, string userId, string EmailId)
|
|
{
|
|
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
|
|
|
|
// Fetch the metadata document for the customer ID
|
|
var metadataDocumentId = GetMetaDocumentKey(appKey, userId);
|
|
MetadataDocumentContact metadataDocument = null;
|
|
try
|
|
{
|
|
var metadataDocumentResponse = await container.ReadItemAsync<MetadataDocumentContact>(metadataDocumentId, new PartitionKey(metadataDocumentId));
|
|
metadataDocument = metadataDocumentResponse.Resource;
|
|
}
|
|
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
{
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Helpers.LogIt(e.Message);
|
|
}
|
|
|
|
if (metadataDocument == null)
|
|
return false;
|
|
|
|
// Determine the partition keys within the date range
|
|
var partitionKeysInDocument = metadataDocument.PartitionKeys;
|
|
// Fetch the audit records for each partition key within the date range
|
|
foreach (var partitionKey in partitionKeysInDocument)
|
|
{
|
|
|
|
ItemResponse<ContactsDocument> response = await container.ReadItemAsync<ContactsDocument>(partitionKey, new PartitionKey(partitionKey));
|
|
if (response == null)
|
|
continue;
|
|
|
|
ContactsDocument t = response.Resource;
|
|
var originalCount = t.Records.Count;
|
|
t.Records = t.Records.Where(item => item.Email != EmailId).ToList();
|
|
var afterFilterCount = t.Records.Count;
|
|
|
|
if (originalCount != afterFilterCount)
|
|
{
|
|
ItemResponse<ContactsDocument> updateResponse = await container.ReplaceItemAsync(
|
|
item: t,
|
|
id: t.id,
|
|
partitionKey: new PartitionKey(partitionKey));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static async Task UpdateContactsDocument(ContactsDocument al)
|
|
{
|
|
if (al.Records.Count == 0)
|
|
return;
|
|
|
|
List<ContactsDocument> lal = await SplitAuditlog(al);
|
|
|
|
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
|
|
|
|
foreach (ContactsDocument ial in lal)
|
|
{
|
|
ItemResponse<ContactsDocument> r = await container.UpsertItemAsync(ial, new PartitionKey(ial.id));
|
|
}
|
|
|
|
await UpdateMetadata(container, lal);
|
|
}
|
|
|
|
static async Task UpdateMetadata(Container container, List<ContactsDocument> lal)
|
|
{
|
|
bool update = false;
|
|
string pKey = GetMetaDocumentKey(lal[0].AppKey, lal[0].UserId);
|
|
MetadataDocument md = null;
|
|
try
|
|
{
|
|
ItemResponse<MetadataDocument> response =
|
|
await container.ReadItemAsync<MetadataDocument>(pKey, new PartitionKey(pKey));
|
|
md = response.Resource;
|
|
}
|
|
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
{
|
|
md = new MetadataDocument()
|
|
{
|
|
id = GetMetaDocumentKey(lal[0].AppKey, lal[0].UserId),
|
|
PartitionKeys = new List<string>()
|
|
};
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Helpers.LogIt(e.Message);
|
|
return;
|
|
}
|
|
|
|
if (md == null)
|
|
{
|
|
// Helpers.LogIt("Something ugly happened!");
|
|
return;
|
|
}
|
|
|
|
foreach (ContactsDocument log in lal)
|
|
{
|
|
if (md.PartitionKeys.Contains(log.id))
|
|
continue;
|
|
md.PartitionKeys.Add(log.id);
|
|
update = true;
|
|
}
|
|
|
|
if (update)
|
|
{
|
|
try
|
|
{
|
|
ItemResponse<MetadataDocument> r = await container.UpsertItemAsync(md, new PartitionKey(pKey));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Helpers.LogIt(e.Message);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static async Task<List<ContactsDocument>> SplitAuditlog(ContactsDocument al)
|
|
{
|
|
List<ContactsDocument> lal = new List<ContactsDocument>();
|
|
var sortedRecords = al.Records.OrderBy(record => record.EventTime).ToList();
|
|
|
|
var currentGroup = new List<ContactRecord>();
|
|
var currentGroupSize = 0;
|
|
|
|
int MaxDocumentSizeInBytes = 2 * 1024 * 1024; // 2MB
|
|
|
|
int index = al.Index; // start for index passed in
|
|
foreach (var record in sortedRecords)
|
|
{
|
|
var recordSize = record.CalculateRecordSize();
|
|
|
|
if (currentGroupSize + recordSize > MaxDocumentSizeInBytes)
|
|
{
|
|
ContactsDocument i = new ContactsDocument();
|
|
i.Index = index++;
|
|
i.Records = currentGroup;
|
|
i.AppKey = al.AppKey;
|
|
i.UserId = al.UserId;
|
|
lal.Add(i);
|
|
|
|
currentGroup = new List<ContactRecord>();
|
|
currentGroupSize = 0;
|
|
}
|
|
|
|
currentGroup.Add(record);
|
|
currentGroupSize += recordSize;
|
|
}
|
|
|
|
if (currentGroup.Any())
|
|
{
|
|
ContactsDocument i = new ContactsDocument();
|
|
i.Index = index++;
|
|
i.Records = currentGroup;
|
|
i.AppKey = al.AppKey;
|
|
i.UserId = al.UserId;
|
|
lal.Add(i);
|
|
}
|
|
|
|
return lal;
|
|
}
|
|
|
|
|
|
public static async Task<ContactsDocument> GetContactDocument(string key)
|
|
{
|
|
try
|
|
{
|
|
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
|
|
ItemResponse<ContactsDocument> response = await container.ReadItemAsync<ContactsDocument>(key, new PartitionKey(key));
|
|
if (response == null)
|
|
return null;
|
|
|
|
ContactsDocument t = response.Resource;
|
|
return t;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static async Task<MetadataDocumentContact> GetMetadataDocument(string appKey, string userId)
|
|
{
|
|
MetadataDocumentContact md = null;
|
|
string pKey = GetMetaDocumentKey(appKey, userId);
|
|
string id = GetDocumentId(appKey, userId);
|
|
|
|
PartitionKey partitionKey = new PartitionKeyBuilder()
|
|
.Add(pKey)
|
|
.Build();
|
|
Container container = cosmosClient.GetContainer(DatabaseName, ContainerName);
|
|
try
|
|
{
|
|
ItemResponse<MetadataDocumentContact> response =
|
|
await container.ReadItemAsync<MetadataDocumentContact>(pKey, partitionKey);
|
|
md = response.Resource;
|
|
}
|
|
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
{
|
|
md = new MetadataDocumentContact()
|
|
{
|
|
id = id,
|
|
PartitionKeys = new List<string>()
|
|
};
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Helpers.LogIt(e.Message);
|
|
return null;
|
|
}
|
|
|
|
if (md == null)
|
|
{
|
|
// Helpers.LogIt("Something ugly happened!");
|
|
return null;
|
|
}
|
|
return md;
|
|
}
|
|
|
|
static string GetMetaDocumentKey(string appKey, string userId)
|
|
{
|
|
return $"{appKey}-{userId}-meta";
|
|
}
|
|
|
|
static string GetDocumentId(string appKey, string userId)
|
|
{
|
|
return $"{appKey}-{userId}";
|
|
}
|
|
}
|
|
}
|