protected override async Task <List <int> > SaveExecuteAsync(List <PrintingTemplateForSave> entities, bool returnIds) { var definitionedCollections = new string[] { nameof(Document), nameof(Resource), nameof(Agent), nameof(Lookup) }; foreach (var(entity, index) in entities.Indexed()) { if (entity.Usage == TemplateUsages.FromSearchAndDetails || entity.Usage == TemplateUsages.FromDetails) { if (entity.Collection == null) { ModelState.AddError($"[{index}].Collection", _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["Template_Collection"]]); } else { if (definitionedCollections.Contains(entity.Collection)) { // DefinitionId is required when querying by Id if (entity.Usage == TemplateUsages.FromDetails && entity.DefinitionId == null) { ModelState.AddError($"[{index}].DefinitionId", _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["Template_DefinitionId"]]); } } else { entity.DefinitionId = null; } } } if (entity.Usage == TemplateUsages.FromReport) { if (entity.ReportDefinitionId == null) { ModelState.AddError($"[{index}].ReportDefinitionId", _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["Template_ReportDefinitionId"]]); } } // TODO Check that DefinitionId is compatible with Collection var duplicateKeys = entity .Parameters .Select(e => e.Key) .GroupBy(e => e) .Where(e => e.Count() > 1) .Select(e => e.FirstOrDefault()) .ToHashSet(); // Validate parameters foreach (var(parameter, parameterIndex) in entity.Parameters.Indexed()) { if (!TemplexVariable.IsValidVariableName(parameter.Key)) { var path = $"[{index}].{nameof(entity.Parameters)}[{parameterIndex}].{nameof(parameter.Key)}"; var msg = "Invalid Key. Valid keys contain only alphanumeric characters, dollar symbols, and underscores and do not start with a number."; ModelState.AddError(path, msg); } else if (duplicateKeys.Contains(parameter.Key)) { var path = $"[{index}].{nameof(entity.Parameters)}[{parameterIndex}].{nameof(parameter.Key)}"; var msg = $"The Key '{parameter.Key}' is used more than once."; ModelState.AddError(path, msg); } } } SaveOutput result = await _behavior.Repository.PrintingTemplates__Save( entities : entities, returnIds : returnIds, validateOnly : ModelState.IsError, top : ModelState.RemainingErrors, userId : UserId); AddErrorsAndThrowIfInvalid(result.Errors); return(result.Ids); }
protected override async Task <List <int> > SaveExecuteAsync(List <NotificationTemplateForSave> entities, bool returnIds) { #region Validation var definitionedCollections = new string[] { nameof(Document), nameof(Resource), nameof(Agent), nameof(Lookup) }; foreach (var(entity, index) in entities.Indexed()) { if (entity.Cardinality == Cardinalities.Bulk) { // ListExpression if (string.IsNullOrWhiteSpace(entity.ListExpression)) { var path = $"[{index}].{nameof(entity.ListExpression)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["NotificationTemplate_ListExpression"]]; ModelState.AddError(path, msg); } else { try { TemplexBase.Parse(entity.ListExpression); } catch { var path = $"[{index}].{nameof(entity.ListExpression)}"; var msg = _localizer["Error_InvalidTemplateExpression0", entity.ListExpression]; ModelState.AddError(path, msg); } } // AddressExpression if (string.IsNullOrWhiteSpace(entity.AddressExpression)) { var path = $"[{index}].{nameof(entity.AddressExpression)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["NotificationTemplate_AddressExpression"]]; ModelState.AddError(path, msg); } else { try { TemplexBase.Parse(entity.AddressExpression); } catch { var path = $"[{index}].{nameof(entity.AddressExpression)}"; var msg = _localizer["Error_InvalidTemplateExpression0", entity.AddressExpression]; ModelState.AddError(path, msg); } } } if (entity.Trigger == Triggers.Automatic) { // Schedule if (string.IsNullOrWhiteSpace(entity.Schedule)) { var path = $"[{index}].{nameof(entity.Schedule)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["NotificationTemplate_Schedule"]]; ModelState.AddError(path, msg); } else { string faultyCron = null; try { var crons = entity.Schedule.Split(';') .Where(e => !string.IsNullOrWhiteSpace(e)) .Select(e => e.Trim()); foreach (var cron in crons) { faultyCron = cron; CronExpression.Parse(cron); } } catch { var path = $"[{index}].{nameof(entity.Schedule)}"; var msg = _localizer["Error_InvalidCronExpression0", faultyCron]; ModelState.AddError(path, msg); } } if (string.IsNullOrWhiteSpace(entity.ConditionExpression)) { // Doesn't matter } else { try { TemplexBase.Parse(entity.ConditionExpression); } catch { var path = $"[{index}].{nameof(entity.ConditionExpression)}"; var msg = _localizer["Error_InvalidTemplateExpression0", entity.ConditionExpression]; ModelState.AddError(path, msg); } } } if (entity.Trigger == Triggers.Manual) { // Usage if (string.IsNullOrWhiteSpace(entity.Usage)) { var path = $"[{index}].{nameof(entity.Usage)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["Template_Usage"]]; ModelState.AddError(path, msg); } else if (entity.Usage == TemplateUsages.FromSearchAndDetails || entity.Usage == TemplateUsages.FromDetails) { if (string.IsNullOrWhiteSpace(entity.Collection)) { var path = $"[{index}].{nameof(entity.Collection)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["Template_Collection"]]; ModelState.AddError(path, msg); } else { if (definitionedCollections.Contains(entity.Collection)) { // DefinitionId is required when querying by Id if (entity.Usage == TemplateUsages.FromDetails && entity.DefinitionId == null) { var path = $"[{index}].{nameof(entity.DefinitionId)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["Template_DefinitionId"]]; ModelState.AddError(path, msg); } } else { entity.DefinitionId = null; } } } else if (entity.Usage == TemplateUsages.FromReport) { if (entity.ReportDefinitionId == null) { var path = $"[{index}].{nameof(entity.ReportDefinitionId)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["Template_ReportDefinitionId"]]; ModelState.AddError(path, msg); } } // TODO Check that DefinitionId is compatible with Collection } if (entity.Channel == Channels.Email) { // Subject if (string.IsNullOrWhiteSpace(entity.Subject)) { var path = $"[{index}].{nameof(entity.Subject)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["NotificationTemplate_Subject"]]; ModelState.AddError(path, msg); } else { try { TemplateTree.Parse(entity.Subject); } catch { var path = $"[{index}].{nameof(entity.Subject)}"; var msg = _localizer["Error_InvalidTemplate"]; ModelState.AddError(path, msg); } } } // Body if (!string.IsNullOrWhiteSpace(entity.Body)) { if (entity.Channel == Channels.Sms) { const int maxSmsExpressionLength = 1024; if (entity.Body.Length > maxSmsExpressionLength) { var path = $"[{index}].{nameof(entity.Body)}"; var msg = _localizer[ErrorMessages.Error_Field0LengthMaximumOf1, _localizer["Template_Body"], maxSmsExpressionLength]; ModelState.AddError(path, msg); } } try { TemplateTree.Parse(entity.Body); } catch { var path = $"[{index}].{nameof(entity.Body)}"; var msg = _localizer["Error_InvalidTemplate"]; ModelState.AddError(path, msg); } } // Caption try { TemplateTree.Parse(entity.Caption); } catch { var path = $"[{index}].{nameof(entity.Caption)}"; var msg = _localizer["Error_InvalidTemplate"]; ModelState.AddError(path, msg); } var duplicateKeys = entity .Parameters .Select(e => e.Key) .GroupBy(e => e) .Where(e => e.Count() > 1) .Select(e => e.FirstOrDefault()) .ToHashSet(); // Parameters foreach (var(parameter, parameterIndex) in entity.Parameters.Indexed()) { if (!TemplexVariable.IsValidVariableName(parameter.Key)) { var path = $"[{index}].{nameof(entity.Parameters)}[{parameterIndex}].{nameof(parameter.Key)}"; var msg = "Invalid Key. Valid keys contain only alphanumeric characters, dollar symbols, and underscores and do not start with a number."; ModelState.AddError(path, msg); } else if (duplicateKeys.Contains(parameter.Key)) { var path = $"[{index}].{nameof(entity.Parameters)}[{parameterIndex}].{nameof(parameter.Key)}"; var msg = $"The Key '{parameter.Key}' is used more than once."; ModelState.AddError(path, msg); } } // Attachments foreach (var(attachment, attachmentIndex) in entity.Attachments.Indexed()) { if (!string.IsNullOrWhiteSpace(attachment.ContextOverride)) { try { TemplexBase.Parse(attachment.ContextOverride); } catch { var path = $"[{index}].{nameof(entity.Attachments)}[{attachmentIndex}].{nameof(attachment.ContextOverride)}"; var msg = _localizer["Error_InvalidTemplateExpression0", attachment.ContextOverride]; ModelState.AddError(path, msg); } } if (!string.IsNullOrWhiteSpace(attachment.DownloadNameOverride)) { try { TemplateTree.Parse(attachment.DownloadNameOverride); } catch { var path = $"[{index}].{nameof(entity.Attachments)}[{attachmentIndex}].{nameof(attachment.DownloadNameOverride)}"; var msg = _localizer["Error_InvalidTemplate0", attachment.DownloadNameOverride]; ModelState.AddError(path, msg); } } } // Subscribers foreach (var(subscriber, subscriberIndex) in entity.Subscribers.Indexed()) { if (subscriber.AddressType == AddressTypes.User) { if (subscriber.UserId == null) { var path = $"[{index}].{nameof(entity.Subscribers)}[{subscriberIndex}].{nameof(subscriber.UserId)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["NotificationTemplate_User"]]; ModelState.AddError(path, msg); } } if (subscriber.AddressType == AddressTypes.Text) { if (entity.Channel == Channels.Email) { if (string.IsNullOrWhiteSpace(subscriber.Email)) { var path = $"[{index}].{nameof(entity.Subscribers)}[{subscriberIndex}].{nameof(subscriber.Email)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["NotificationTemplate_Email"]]; ModelState.AddError(path, msg); } else { try { TemplateTree.Parse(subscriber.Email); } catch { var path = $"[{index}].{nameof(entity.Subscribers)}[{subscriberIndex}].{nameof(subscriber.Email)}"; var msg = _localizer["Error_InvalidTemplate"]; ModelState.AddError(path, msg); } } } if (entity.Channel == Channels.Sms) { if (string.IsNullOrWhiteSpace(subscriber.Phone)) { var path = $"[{index}].{nameof(entity.Subscribers)}[{subscriberIndex}].{nameof(subscriber.Phone)}"; var msg = _localizer[ErrorMessages.Error_Field0IsRequired, _localizer["NotificationTemplate_Phone"]]; ModelState.AddError(path, msg); } else { try { TemplateTree.Parse(subscriber.Phone); } catch { var path = $"[{index}].{nameof(entity.Subscribers)}[{subscriberIndex}].{nameof(subscriber.Phone)}"; var msg = _localizer["Error_InvalidTemplate"]; ModelState.AddError(path, msg); } } } } } } #endregion SaveOutput result = await _behavior.Repository.NotificationTemplates__Save( entities : entities, returnIds : returnIds, validateOnly : ModelState.IsError, top : ModelState.RemainingErrors, userId : UserId); AddErrorsAndThrowIfInvalid(result.Errors); return(result.Ids); }