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.

311 lines
13 KiB

using Azure.Messaging.ServiceBus;
using Microsoft.Extensions.Logging;
using System;
using System.Text.Json;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.Functions.Worker;
using System.Net;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using FromBodyAttribute = Microsoft.Azure.Functions.Worker.Http.FromBodyAttribute;
namespace CDP
{
public class MetaProcessor
{
private readonly ILogger<MetaProcessor> _logger;
private static Lazy<ServiceBusClient> lazyBusClient = new Lazy<ServiceBusClient>(InitializeServiceBusClient);
private static ServiceBusClient _serviceBusClient = lazyBusClient.Value;
public MetaProcessor(ILogger<MetaProcessor> logger)
{
_logger = logger;
}
private static ServiceBusClient InitializeServiceBusClient()
{
return new ServiceBusClient(Constants.SvcBusConnectionString);
}
public static async Task PublishBatchJobs(List<Job> jobs)
{
//Job[] jobsCopy = jobs.ToArray();
var sender = _serviceBusClient.CreateSender("mail-events-queue");
ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();
jobs.ForEach(job =>
{
var msg = new ServiceBusMessage(JsonSerializer.Serialize(job));
bool isAdded = batch.TryAddMessage(msg);
});
await sender.SendMessagesAsync(batch);
}
public static async Task PublishJob(Job job)
{
var sender = _serviceBusClient.CreateSender("mail-events-queue");
ServiceBusMessage msg = new ServiceBusMessage(JsonSerializer.Serialize(job));
await sender.SendMessageAsync(msg);
}
[Function("MailMetaProcessor")]
public async Task<Job> MailMetaProcessor([ActivityTrigger] MailRecord mailRecord, FunctionContext functionContext)
{
Job job = await TriggerMailProcessor(mailRecord);
return job;
}
[Function("MailMetaOrchestrator")]
public async Task<Job> MailMetaOrchestrator([OrchestrationTrigger] TaskOrchestrationContext ctx)
{
try
{
MailRecord record = ctx.GetInput<MailRecord>();
string jobId = await ctx.CallActivityAsync<string>(nameof(AddProtectionAudits), record);
Job job = await ctx.CallActivityAsync<Job>(nameof(MailMetaProcessor), record);
string revId = await ctx.CallActivityAsync<string>(nameof(AddMailCompundRevision), record);
return job;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new Job() { AppKey = "", EventType = JobType.MailMetaProcessing, Id = "failed" };
}
}
[Function("AddMailMetaDurable")]
public async Task<HttpResponseData> AddMailMetaDurable([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
[FromBody] MailRecord recordMail,
[DurableClient] DurableTaskClient client)
{
bool isValid = true;
//bool isValid = await CDPLite.CheckJwtRequest(req);
if (!isValid)
{
HttpResponseData res = req.CreateResponse(HttpStatusCode.Unauthorized);
return res;
}
try
{
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(MailMetaOrchestrator), recordMail);
_logger.LogInformation("created instance: {0}", instanceId);
return client.CreateCheckStatusResponse(req, instanceId);
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
HttpResponseData response = req.CreateResponse(HttpStatusCode.InternalServerError);
return response;
}
}
[Function("AddMailMeta")]
public async Task<ActionResult> AddMailMeta([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req, [FromBody] MailRecord recordMail)
{
bool isValid = true;
//bool isValid = await CDPLite.CheckJwtRequest(req);
if (!isValid)
{
return new UnauthorizedObjectResult("Jwt has expired please validate");
}
try
{
MailRecord mailRecord = recordMail;
//_logger.LogInformation(JsonSerializer.Serialize(recordMail));
string res = await TriggerProtectionAuditsJob(mailRecord);
res = await AddMailCompoundRevisionInternal(mailRecord);
_logger.LogInformation($"protection audits? {res}");
Job job = await TriggerMailProcessor(mailRecord);
return new OkObjectResult(job);
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
return new StatusCodeResult(500);
}
}
[Function("AddMailForwardingRequest")]
public async Task<IActionResult> AddMailForwardingRequest([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
ForwardMailDto forwardMail;
try
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
_logger.LogInformation("requestbody: {0}", requestBody);
forwardMail = JsonSerializer.Deserialize<ForwardMailDto>(requestBody);
}
catch (Exception ex)
{
_logger.LogInformation(ex.ToString());
return new StatusCodeResult(500);
}
string appKey = forwardMail.AppKey;
var userId = Helpers.HashAndShortenText(forwardMail.SenderEmail.ToLower());
var fr = await CDPDB.GetFile(appKey, forwardMail.MailId, userId);
if ((!fr.Policy.CheckAccess("Manage")) && (!fr.Policy.CheckAccess("Owner")))
{
return new UnauthorizedObjectResult("User doesn't have rights to forward this email");
}
RevisionEntry entry = await FileRevision.GetFileRevisionInternal(forwardMail.AppKey, forwardMail.MailId);
if (entry.CompoundDocument == null)
{
return new BadRequestObjectResult("IncorrectMailId");
}
MailMetaRecord mailRecord = JsonSerializer.Deserialize<MailMetaRecord>(entry.CompoundDocument.Contents);
mailRecord.AttachmentDetails.ForEach(async (att) =>
{
forwardMail.ReceiverEmails.ForEach(async (receiver) =>
{
await AddMailForwardPolicy(appKey, att.FileId, att.FileName, forwardMail.SenderEmail, receiver, "Read");
});
});
forwardMail.ReceiverEmails.ForEach(async (receiver) =>
{
await AddMailForwardPolicy(appKey, mailRecord.BodyId, string.Concat(mailRecord.BodyId, "-", "MailBody"), forwardMail.SenderEmail, receiver, "Read");
});
return new OkObjectResult("Done");
}
internal async Task AddMailForwardPolicy(string appKey, string fileId, string fileName, string sender, string receiver, string policy = "Read")
{
AddFileUserDto addFileUserDto = new AddFileUserDto
{
AppKey = appKey,
FileId = fileId,
FileName = fileName,
Email = sender,
EmailToAdd = receiver,
Policy = policy
};
await CDPLite.AddFileUserInternal(addFileUserDto);
}
[Function("AddMailCompundRevision")]
public async Task<string> AddMailCompundRevision([ActivityTrigger] MailRecord record, FunctionContext context)
{
return await AddMailCompoundRevisionInternal(record);
}
internal async Task<string> AddMailCompoundRevisionInternal(MailRecord record)
{
RevisionDocument doc = new RevisionDocument
{
RevisionId = Guid.NewGuid().ToString(),
RevisionDate = DateTime.UtcNow,
EditedBy = record.SenderEmail,
Comments = "MailBody"
};
MailMetaRecord mailMeta = new MailMetaRecord
{
AppKey = record.AppKey,
SenderEmail = record.SenderEmail,
BodyContent = record.BodyContent,
BodyId = record.MailId,
AttachmentDetails = record.AttachmentDetails
};
CompoundDocument compound = new CompoundDocument
{
Id = Guid.NewGuid().ToString(),
AppKey = record.AppKey,
Contents = JsonSerializer.Serialize(mailMeta),
DocumentType = "MailRecord"
};
string revisionId = await FileRevision.AddMailBodyRevision(doc, compound, record.AppKey, record.MailId);
return revisionId;
}
[Function("AddProtectionAudits")]
public async Task<string> AddProtectionAudits([ActivityTrigger] MailRecord record, FunctionContext functionContext)
{
var res = await TriggerProtectionAuditsJob(record);
return res;
}
internal async Task<string> TriggerProtectionAuditsJob(MailRecord record)
{
try
{
string userId = Helpers.HashAndShortenText(record.SenderEmail);
string message = string.Format($"{record.SenderEmail} protected an email body with id: {record.MailId}.");
List<AuditEventMetadata> auditEvents = new List<AuditEventMetadata>();
AuditEventMetadata auditEvent = new AuditEventMetadata { Action = "Addded", FileId = record.MailId, FileName = "Outlook-Mail-Body", Message = message, UserId = userId };
auditEvents.Add(auditEvent);
record.AttachmentDetails.ForEach((att) =>
{
message = string.Format($"{record.SenderEmail} protected the email attachment {att.FileName} with id: {att.FileId}.");
AuditEventMetadata attachmentEvent = new AuditEventMetadata { Action = "Added", FileId = att.FileId, FileName = att.FileName, Message = message, UserId = userId };
auditEvents.Add(attachmentEvent);
});
Job job = await CDPLite.AddAuditsBatchedEvent(auditEvents, record.AppKey);
await PublishJob(job);
_logger.LogInformation(JsonSerializer.Serialize(job));
return "Done";
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
throw ex;
}
}
internal async Task<Job> TriggerMailProcessor(MailRecord mailRecord)
{
string Connection = Constants.StorageConnString;
var blobSvc = new BlobServiceClient(Connection);
var blobClient = blobSvc.GetBlobContainerClient(mailRecord.AppKey.ToLower());
if (!blobClient.Exists())
{
await blobClient.CreateAsync();
}
byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(JsonSerializer.Serialize(mailRecord));
string jobId = Guid.NewGuid().ToString();
var blob = blobClient.GetBlobClient(jobId);
Stream fs = new MemoryStream(fileBytes);
try
{
await blob.UploadAsync(fs);
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
throw ex;
}
Job job = new Job { AppKey = mailRecord.AppKey, EventType = JobType.MailMetaProcessing, Id = jobId };
await PublishJob(job);
return job;
}
}
public class MailMetaRecord
{
public required string AppKey { get; set; }
public required string SenderEmail { get; set; }
public required string BodyId { get; set; }
public required string BodyContent { get; set; } //encrypted body
public required List<AttachmentDetails> AttachmentDetails { get; set; }
}
public class ForwardMailDto
{
public string SenderEmail { get; set; }
public List<string> ReceiverEmails { get; set; }
public string MailId { get; set; }
public string AppKey { get; set; }
}
}