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));
        }
Пример #2
0
        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());
        }
Пример #4
0
        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));
        }
Пример #6
0
        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);
        }