public async Task <OpenApiResult> GenerateTemplateAsync( IOpenApiContext context, CreateNotificationsRequest body) { // We can guarantee tenant Id is available because it's part of the Uri. ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false); var registeredCommunicationChannels = new List <CommunicationType>() { CommunicationType.WebPush, CommunicationType.Email, CommunicationType.Sms }; // TODO: In the future, check if these registeredCommunicationChannels are actually usable for the current Tenant. if (registeredCommunicationChannels is null || registeredCommunicationChannels.Count == 0) { throw new Exception($"There are no communication channel set up for the user {body.UserIds[0]} for notification type {body.NotificationType} for tenant {tenant.Id}"); } // Gets the AzureBlobTemplateStore INotificationTemplateStore templateStore = await this.tenantedTemplateStoreFactory.GetTemplateStoreForTenantAsync(tenant).ConfigureAwait(false); NotificationTemplate?responseTemplate = await this.generateTemplateComposer.GenerateTemplateAsync(templateStore, body.Properties, registeredCommunicationChannels, body.NotificationType).ConfigureAwait(false); return(this.OkResult(responseTemplate)); }
public async Task ExecuteAsync( [ActivityTrigger] IDurableActivityContext context, ILogger logger) { TenantedFunctionData <UserNotification> request = context.GetInput <TenantedFunctionData <UserNotification> >(); if (request.Payload.Id is null) { throw new Exception("Notification has to be created before being dispatched via Third Party Delivery Channels."); } ITenant tenant = await this.tenantProvider.GetTenantAsync(request.TenantId).ConfigureAwait(false); logger.LogInformation( "Executing DispatchNotificationActivity for notification of type {notificationType} for user {userId}", request.Payload.NotificationType, request.Payload.UserId); if (request.Payload.DeliveryChannelConfiguredPerCommunicationType is null) { throw new Exception($"There is no communication channels and delivery channel defined the notification type: {request.Payload.NotificationType}"); } var registeredCommunicationChannels = request.Payload.DeliveryChannelConfiguredPerCommunicationType.Keys.ToList(); if (registeredCommunicationChannels.Count == 0) { throw new Exception($"There is no communication channels and delivery channel defined the notification type: {request.Payload.NotificationType}"); } // Gets the AzureBlobTemplateStore INotificationTemplateStore templateStore = await this.tenantedTemplateStoreFactory.GetTemplateStoreForTenantAsync(tenant).ConfigureAwait(false); NotificationTemplate notificationTemplate = await this.generateTemplateComposer.GenerateTemplateAsync(templateStore, request.Payload.Properties, registeredCommunicationChannels, request.Payload.NotificationType).ConfigureAwait(false); if (notificationTemplate is null) { throw new Exception("There was an issue generating notification templates."); } foreach (KeyValuePair <CommunicationType, string> keyValuePair in request.Payload.DeliveryChannelConfiguredPerCommunicationType) { switch (keyValuePair.Value) { case DeliveryChannel.Airship: if (notificationTemplate.WebPushTemplate != null && keyValuePair.Key == CommunicationType.WebPush) { await this.SendWebPushNotificationAsync(request.Payload.UserId, request.Payload.NotificationType, request.Payload.Id, tenant, notificationTemplate.WebPushTemplate).ConfigureAwait(false); } break; default: throw new Exception( $"Currently the Delivery Channel is limited to {DeliveryChannel.Airship}"); } } }
public async Task <OpenApiResult> CreateTemplateAsync( IOpenApiContext context, ICommunicationTemplate body, [OpenApiParameter("If-None-Match")] string etag) { if (string.IsNullOrWhiteSpace(body.NotificationType)) { throw new OpenApiNotFoundException("The NotificationType was not found in the object"); } if (string.IsNullOrWhiteSpace(body.ContentType)) { throw new OpenApiNotFoundException("The ContentType was not found in the object"); } // We can guarantee tenant Id is available because it's part of the Uri. ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false); // Gets the AzureBlobTemplateStore INotificationTemplateStore store = await this.tenantedTemplateStoreFactory.GetTemplateStoreForTenantAsync(tenant).ConfigureAwait(false); try { if (body is EmailTemplate emailTemplate) { emailTemplate.ETag = etag; await store.CreateOrUpdate(body.NotificationType, CommunicationType.Email, emailTemplate.ETag, emailTemplate).ConfigureAwait(false); } else if (body is SmsTemplate smsTemplate) { smsTemplate.ETag = etag; await store.CreateOrUpdate(body.NotificationType, CommunicationType.Sms, smsTemplate.ETag, smsTemplate).ConfigureAwait(false); } else if (body is WebPushTemplate webPushTemplate) { webPushTemplate.ETag = etag; await store.CreateOrUpdate(body.NotificationType, CommunicationType.WebPush, webPushTemplate.ETag, webPushTemplate).ConfigureAwait(false); } else { // this should be removed in future updates throw new OpenApiNotFoundException($"The template for ContentType: {body.ContentType} is not a valid content type"); } } catch (StorageException e) { if (e?.RequestInformation?.HttpStatusCode == (int)System.Net.HttpStatusCode.PreconditionFailed) { throw new OpenApiBadRequestException("Precondition failure. Blob's ETag does not match ETag provided."); } throw; } return(this.OkResult()); }
public async Task GivenIHaveCreatedAndStoredANotificationTemplate(Table table) { ITenantedNotificationTemplateStoreFactory storeFactory = this.serviceProvider.GetRequiredService <ITenantedNotificationTemplateStoreFactory>(); IJsonSerializerSettingsProvider serializerSettingsProvider = this.serviceProvider.GetRequiredService <IJsonSerializerSettingsProvider>(); NotificationTemplate notificationTemplate = BuildNotificationTemplateFrom(table.Rows[0], serializerSettingsProvider.Instance); INotificationTemplateStore store = await storeFactory.GetTemplateStoreForTenantAsync(this.featureContext.GetTransientTenant()).ConfigureAwait(false); EmailTemplate?result = await store.CreateOrUpdate("testshouldbreak", CommunicationType.Email, null, notificationTemplate.EmailTemplate !).ConfigureAwait(false); this.scenarioContext.Set(result); }
/// <inheritdoc/> public async Task <NotificationTemplate> GenerateTemplateAsync( INotificationTemplateStore templateStore, IPropertyBag body, List <CommunicationType> registeredCommunicationChannels, string notificationType) { EmailTemplate? emailTemplate = null; SmsTemplate? smsTemplate = null; WebPushTemplate?webPushTemplate = null; IReadOnlyDictionary <string, object> propertiesDictionary = body.AsDictionaryRecursive(); var propertiesHash = Hash.FromReadOnlyDictionary(propertiesDictionary); foreach (CommunicationType channel in registeredCommunicationChannels) { switch (channel) { case CommunicationType.Email: try { (EmailTemplate, string?)emailRawTemplate = await templateStore.GetAsync <EmailTemplate>(notificationType, CommunicationType.Email).ConfigureAwait(false); string?emailBody = await this.GenerateTemplateForFieldAsync(emailRawTemplate.Item1.Body, propertiesHash).ConfigureAwait(false); string?emailSubject = await this.GenerateTemplateForFieldAsync(emailRawTemplate.Item1.Subject, propertiesHash).ConfigureAwait(false); if (string.IsNullOrEmpty(emailSubject)) { this.logger.LogError($"The template for the communication type Email doesn't have subject which is necessary to trigger a {notificationType} notification."); break; } if (string.IsNullOrEmpty(emailBody)) { this.logger.LogError($"The template for the communication type Email doesn't have body which is necessary to trigger a {notificationType} notification."); break; } emailTemplate = new EmailTemplate( notificationType, emailSubject, emailBody); } catch (Exception) { this.logger.LogError("The template for the communication type Email doesn't exist"); } break; case CommunicationType.Sms: try { (SmsTemplate, string?)smsRawTemplate = await templateStore.GetAsync <SmsTemplate>(notificationType, CommunicationType.Sms).ConfigureAwait(false); string?smsBody = await this.GenerateTemplateForFieldAsync(smsRawTemplate.Item1.Body !, propertiesHash).ConfigureAwait(false); if (string.IsNullOrEmpty(smsBody)) { this.logger.LogError($"The template for the communication type Sms doesn't have body which is necessary to trigger a {notificationType} notification."); break; } smsTemplate = new SmsTemplate(notificationType, smsBody); } catch (Exception) { this.logger.LogError("The template for the communication type Sms doesn't exist"); } break; case CommunicationType.WebPush: try { (WebPushTemplate, string?)webPushRawTemplate = await templateStore.GetAsync <WebPushTemplate>(notificationType, CommunicationType.WebPush).ConfigureAwait(false); string?webPushTitle = await this.GenerateTemplateForFieldAsync(webPushRawTemplate.Item1.Title, propertiesHash).ConfigureAwait(false); string?webPushBody = await this.GenerateTemplateForFieldAsync(webPushRawTemplate.Item1.Body, propertiesHash).ConfigureAwait(false); string?webPushImage = await this.GenerateTemplateForFieldAsync(webPushRawTemplate.Item1.Image, propertiesHash).ConfigureAwait(false); string?actionUrl = await this.GenerateTemplateForFieldAsync(webPushRawTemplate.Item1.ActionUrl, propertiesHash).ConfigureAwait(false); if (string.IsNullOrEmpty(webPushTitle)) { this.logger.LogError($"The template for the communication type WebPush doesn't have title which is necessary to trigger a {notificationType} notification."); break; } if (string.IsNullOrEmpty(webPushBody)) { this.logger.LogError($"The template for the communication type WebPush doesn't have body which is necessary to trigger a {notificationType} notification."); break; } webPushTemplate = new WebPushTemplate( notificationType, webPushTitle, webPushBody, webPushImage, actionUrl); } catch (Exception) { this.logger.LogError("The template for the communication type WebPush doesn't exist"); } break; } } return(new NotificationTemplate( notificationType, smsTemplate, emailTemplate, webPushTemplate)); }
public async Task <OpenApiResult> GetTemplateAsync( IOpenApiContext context, string notificationType, CommunicationType communicationType) { // We can guarantee tenant Id is available because it's part of the Uri. ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false); INotificationTemplateStore store = await this.tenantedTemplateStoreFactory.GetTemplateStoreForTenantAsync(tenant).ConfigureAwait(false); HalDocument?response = null; string? eTag = null; // Gets the template by notificationType switch (communicationType) { case CommunicationType.Email: (EmailTemplate, string?)emailTemplateWrapper = await store.GetAsync <EmailTemplate>(notificationType, communicationType).ConfigureAwait(false); if (emailTemplateWrapper.Item1 is null) { throw new OpenApiNotFoundException($"The notification template for notificationType {notificationType} and communicationType {communicationType} was not found."); } // Add etag to the EmailTemplate eTag = emailTemplateWrapper.Item2; emailTemplateWrapper.Item1.ETag = emailTemplateWrapper.Item2; response = await this.emailTemplateMapper.MapAsync(emailTemplateWrapper.Item1, context).ConfigureAwait(false); break; case CommunicationType.Sms: (SmsTemplate, string?)smsTemplateWrapper = await store.GetAsync <SmsTemplate>(notificationType, communicationType).ConfigureAwait(false); if (smsTemplateWrapper.Item1 is null) { throw new OpenApiNotFoundException($"The notification template for notificationType {notificationType} and communicationType {communicationType} was not found."); } // Add etag to the SmsTemplate eTag = smsTemplateWrapper.Item2; smsTemplateWrapper.Item1.ETag = smsTemplateWrapper.Item2; response = await this.smsTemplateMapper.MapAsync(smsTemplateWrapper.Item1, context).ConfigureAwait(false); break; case CommunicationType.WebPush: (WebPushTemplate, string?)webpushWrapper = await store.GetAsync <WebPushTemplate>(notificationType, communicationType).ConfigureAwait(false); if (webpushWrapper.Item1 is null) { throw new OpenApiNotFoundException($"The notification template for notificationType {notificationType} and communicationType {communicationType} was not found."); } // Add etag to the WebPushTemplate eTag = webpushWrapper.Item2; webpushWrapper.Item1.ETag = webpushWrapper.Item2; response = await this.webPushTemplateMapper.MapAsync(webpushWrapper.Item1, context).ConfigureAwait(false); break; } if (response is null) { throw new OpenApiNotFoundException($"The notification template for notificationType {notificationType} and communicationType {communicationType} was not found."); } OpenApiResult okResult = this.OkResult(response, "application/json"); if (!string.IsNullOrEmpty(eTag)) { okResult.Results.Add("ETag", eTag); } return(okResult); }