From d98c12e6e072c4bb64562fd156acea9283ae3499 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Mon, 18 Mar 2024 16:58:36 +0300 Subject: [PATCH 01/33] Suuport Azure Communication SMS --- Directory.Packages.props | 1 + OrchardCore.sln | 7 + .../Activities/SmsTask.cs | 68 +++++++++ .../OrchardCore.Sms.Azure/AdminMenu.cs | 54 +++++++ .../Controllers/AdminController.cs | 114 +++++++++++++++ .../Drivers/AzureSettingsDisplayDriver.cs | 136 ++++++++++++++++++ .../Drivers/SmsSettingsDisplayDriver.cs | 92 ++++++++++++ .../Drivers/SmsTaskDisplayDriver.cs | 69 +++++++++ .../OrchardCore.Sms.Azure/Manifest.cs | 26 ++++ .../Models/AzureSettings.cs | 10 ++ .../OrchardCore.Sms.Azure.csproj | 31 ++++ .../Services/AzureSmsProvider.cs | 102 +++++++++++++ .../SmsPermissionProvider.cs | 27 ++++ .../OrchardCore.Sms.Azure/SmsPermissions.cs | 8 ++ .../OrchardCore.Sms.Azure/Startup.cs | 60 ++++++++ .../ViewModels/AzureSettingsViewModel.cs | 10 ++ .../ViewModels/SmsSettingsBaseViewModel.cs | 6 + .../ViewModels/SmsSettingsViewModel.cs | 10 ++ .../ViewModels/SmsTaskViewModel.cs | 8 ++ .../ViewModels/SmsTestViewModel.cs | 18 +++ .../Views/Admin/Test.cshtml | 40 ++++++ .../Views/AzureSettings.Edit.cshtml | 35 +++++ .../Views/Items/SmsTask.Fields.Design.cshtml | 12 ++ .../Views/Items/SmsTask.Fields.Edit.cshtml | 35 +++++ .../Items/SmsTask.Fields.Thumbnail.cshtml | 4 + .../Views/NavigationItemText-sms.Id.cshtml | 4 + .../Views/SmsSettings.Edit.cshtml | 11 ++ .../Views/_ViewImports.cshtml | 5 + 28 files changed, 1003 insertions(+) create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSettings.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissionProvider.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTaskViewModel.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/_ViewImports.cshtml diff --git a/Directory.Packages.props b/Directory.Packages.props index 110df2fa9a0..32fcdd399d0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,6 +15,7 @@ + diff --git a/OrchardCore.sln b/OrchardCore.sln index e2b57d6f876..172cbd5cfc9 100644 --- a/OrchardCore.sln +++ b/OrchardCore.sln @@ -525,6 +525,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Rules.Core", "s EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Queries.Core", "src\OrchardCore\OrchardCore.Queries.Core\OrchardCore.Queries.Core.csproj", "{61B358F2-702C-40AA-9DF7-7121248FE6DE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Sms.Azure", "src\OrchardCore.Modules\OrchardCore.Sms.Azure\OrchardCore.Sms.Azure.csproj", "{013C8BBF-6879-4B47-80C9-A466923E45E5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1389,6 +1391,10 @@ Global {61B358F2-702C-40AA-9DF7-7121248FE6DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {61B358F2-702C-40AA-9DF7-7121248FE6DE}.Release|Any CPU.ActiveCfg = Release|Any CPU {61B358F2-702C-40AA-9DF7-7121248FE6DE}.Release|Any CPU.Build.0 = Release|Any CPU + {013C8BBF-6879-4B47-80C9-A466923E45E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {013C8BBF-6879-4B47-80C9-A466923E45E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {013C8BBF-6879-4B47-80C9-A466923E45E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {013C8BBF-6879-4B47-80C9-A466923E45E5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1629,6 +1635,7 @@ Global {E8A1097D-A65A-4B17-A3A2-F50D79552732} = {A066395F-6F73-45DC-B5A6-B4E306110DCE} {4BAA08A2-878C-4B96-86BF-5B3DB2B6C2C7} = {F23AC6C2-DE44-4699-999D-3C478EF3D691} {61B358F2-702C-40AA-9DF7-7121248FE6DE} = {F23AC6C2-DE44-4699-999D-3C478EF3D691} + {013C8BBF-6879-4B47-80C9-A466923E45E5} = {A066395F-6F73-45DC-B5A6-B4E306110DCE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {46A1D25A-78D1-4476-9CBF-25B75E296341} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs new file mode 100644 index 00000000000..0681c89930c --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; +using OrchardCore.Workflows.Abstractions.Models; +using OrchardCore.Workflows.Activities; +using OrchardCore.Workflows.Models; +using OrchardCore.Workflows.Services; + +namespace OrchardCore.Sms.Azure.Activities; + +public class SmsTask : TaskActivity +{ + private readonly ISmsService _smsService; + private readonly IWorkflowExpressionEvaluator _expressionEvaluator; + protected readonly IStringLocalizer S; + + public SmsTask( + ISmsService smsService, + IWorkflowExpressionEvaluator expressionEvaluator, + IStringLocalizer stringLocalizer + ) + { + _smsService = smsService; + _expressionEvaluator = expressionEvaluator; + S = stringLocalizer; + } + + public override LocalizedString DisplayText => S["SMS Task"]; + + public override LocalizedString Category => S["Messaging"]; + + public WorkflowExpression PhoneNumber + { + get => GetProperty(() => new WorkflowExpression()); + set => SetProperty(value); + } + + public WorkflowExpression Body + { + get => GetProperty(() => new WorkflowExpression()); + set => SetProperty(value); + } + + public override IEnumerable GetPossibleOutcomes(WorkflowExecutionContext workflowContext, ActivityContext activityContext) + { + return Outcomes(S["Done"], S["Failed"]); + } + + public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityContext activityContext) + { + var message = new SmsMessage + { + To = await _expressionEvaluator.EvaluateAsync(PhoneNumber, workflowContext, null), + Body = await _expressionEvaluator.EvaluateAsync(Body, workflowContext, null), + }; + + var result = await _smsService.SendAsync(message); + + workflowContext.LastResult = result; + + if (result.Succeeded) + { + return Outcomes("Done"); + } + + return Outcomes("Failed"); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs new file mode 100644 index 00000000000..22bc4290c6c --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs @@ -0,0 +1,54 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Localization; +using OrchardCore.Mvc.Core.Utilities; +using OrchardCore.Navigation; +using OrchardCore.Sms.Azure.Controllers; + +namespace OrchardCore.Sms.Azure; + +public class AdminMenu : INavigationProvider +{ + private static readonly RouteValueDictionary _routeValues = new() + { + { "area", "OrchardCore.Settings" }, + { "groupId", SmsSettings.GroupId }, + }; + + protected readonly IStringLocalizer S; + + public AdminMenu(IStringLocalizer stringLocalizer) + { + S = stringLocalizer; + } + + public Task BuildNavigationAsync(string name, NavigationBuilder builder) + { + if (!NavigationHelper.IsAdminMenu(name)) + { + return Task.CompletedTask; + } + + builder + .Add(S["Configuration"], configuration => configuration + .Add(S["Settings"], settings => settings + .Add(S["SMS"], S["SMS"].PrefixPosition(), sms => sms + .AddClass("sms") + .Id("sms") + .Action("Index", "Admin", _routeValues) + .Permission(SmsPermissions.ManageSmsSettings) + .LocalNav() + ) + .Add(S["SMS Test"], S["SMS Test"].PrefixPosition(), sms => sms + .AddClass("smstest") + .Id("smstest") + .Action(nameof(AdminController.Test), typeof(AdminController).ControllerName(), "OrchardCore.Sms") + .Permission(SmsPermissions.ManageSmsSettings) + .LocalNav() + ) + ) + ); + + return Task.CompletedTask; + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs new file mode 100644 index 00000000000..531619f417d --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs @@ -0,0 +1,114 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Localization; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using OrchardCore.Admin; +using OrchardCore.DisplayManagement.Notify; +using OrchardCore.Sms.Azure.ViewModels; + +namespace OrchardCore.Sms.Azure.Controllers; + +public class AdminController : Controller +{ + private readonly SmsProviderOptions _smsProviderOptions; + private readonly IPhoneFormatValidator _phoneFormatValidator; + private readonly INotifier _notifier; + private readonly IAuthorizationService _authorizationService; + private readonly ISmsProviderResolver _smsProviderResolver; + + protected readonly IHtmlLocalizer H; + protected readonly IStringLocalizer S; + + public AdminController( + IOptions smsProviderOptions, + IPhoneFormatValidator phoneFormatValidator, + ISmsProviderResolver smsProviderResolver, + INotifier notifier, + IAuthorizationService authorizationService, + IHtmlLocalizer htmlLocalizer, + IStringLocalizer stringLocalizer) + { + _smsProviderOptions = smsProviderOptions.Value; + _phoneFormatValidator = phoneFormatValidator; + _smsProviderResolver = smsProviderResolver; + _notifier = notifier; + _authorizationService = authorizationService; + H = htmlLocalizer; + S = stringLocalizer; + } + + [Admin("sms/test", "SmsProviderTest")] + public async Task Test() + { + if (!await _authorizationService.AuthorizeAsync(User, SmsPermissions.ManageSmsSettings)) + { + return Forbid(); + } + + var model = new SmsTestViewModel(); + + PopulateModel(model); + + return View(model); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Test(SmsTestViewModel model) + { + if (!await _authorizationService.AuthorizeAsync(User, SmsPermissions.ManageSmsSettings)) + { + return Forbid(); + } + + if (ModelState.IsValid) + { + var provider = await _smsProviderResolver.GetAsync(model.Provider); + + if (provider is null) + { + ModelState.AddModelError(nameof(model.Provider), S["Please select a valid provider."]); + } + else if (!_phoneFormatValidator.IsValid(model.PhoneNumber)) + { + ModelState.AddModelError(nameof(model.PhoneNumber), S["Please provide a valid phone number."]); + } + else + { + var result = await provider.SendAsync(new SmsMessage() + { + To = model.PhoneNumber, + Body = S["This is a test SMS message."] + }); + + if (result.Succeeded) + { + await _notifier.SuccessAsync(H["The test SMS message has been successfully sent."]); + + return RedirectToAction(nameof(Test)); + } + else + { + await _notifier.ErrorAsync(H["The test SMS message failed to send."]); + } + } + } + + PopulateModel(model); + + return View(model); + } + + private void PopulateModel(SmsTestViewModel model) + { + model.Providers = _smsProviderOptions.Providers + .Where(entry => entry.Value.IsEnabled) + .Select(entry => new SelectListItem(entry.Key, entry.Key)) + .OrderBy(item => item.Text) + .ToArray(); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs new file mode 100644 index 00000000000..6b62289dbcf --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -0,0 +1,136 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Localization; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.Localization; +using OrchardCore.DisplayManagement.Entities; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.ModelBinding; +using OrchardCore.DisplayManagement.Notify; +using OrchardCore.DisplayManagement.Views; +using OrchardCore.Entities; +using OrchardCore.Environment.Shell; +using OrchardCore.Mvc.ModelBinding; +using OrchardCore.Settings; +using OrchardCore.Sms.Azure.Models; +using OrchardCore.Sms.Azure.Services; +using OrchardCore.Sms.Azure.ViewModels; + +namespace OrchardCore.Sms.Azure.Drivers; + +public class AzureSettingsDisplayDriver : SectionDisplayDriver +{ + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IAuthorizationService _authorizationService; + private readonly IPhoneFormatValidator _phoneFormatValidator; + private readonly IDataProtectionProvider _dataProtectionProvider; + private readonly IShellHost _shellHost; + private readonly ShellSettings _shellSettings; + private readonly INotifier _notifier; + + protected readonly IHtmlLocalizer H; + protected readonly IStringLocalizer S; + + public AzureSettingsDisplayDriver( + IHttpContextAccessor httpContextAccessor, + IAuthorizationService authorizationService, + IPhoneFormatValidator phoneFormatValidator, + IDataProtectionProvider dataProtectionProvider, + IShellHost shellHost, + ShellSettings shellSettings, + INotifier notifier, + IHtmlLocalizer htmlLocalizer, + IStringLocalizer stringLocalizer) + { + _httpContextAccessor = httpContextAccessor; + _authorizationService = authorizationService; + _phoneFormatValidator = phoneFormatValidator; + _dataProtectionProvider = dataProtectionProvider; + _shellHost = shellHost; + _shellSettings = shellSettings; + _notifier = notifier; + H = htmlLocalizer; + S = stringLocalizer; + } + + public override IDisplayResult Edit(AzureSettings settings) + { + return Initialize("TwilioSettings_Edit", model => + { + model.IsEnabled = settings.IsEnabled; + model.ConnectionString = settings.ConnectionString; + model.PhoneNumber = settings.PhoneNumber; + }).Location("Content:5#Twilio") + .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) + .OnGroup(SmsSettings.GroupId); + } + + public override async Task UpdateAsync(ISite site, AzureSettings settings, IUpdateModel updater, BuildEditorContext context) + { + var user = _httpContextAccessor.HttpContext?.User; + + if (!context.GroupId.Equals(SmsSettings.GroupId, StringComparison.OrdinalIgnoreCase) + || !await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) + { + return null; + } + + var model = new AzureSettingsViewModel(); + + if (await context.Updater.TryUpdateModelAsync(model, Prefix)) + { + var hasChanges = settings.IsEnabled != model.IsEnabled; + + if (!model.IsEnabled) + { + var smsSettings = site.As(); + + if (hasChanges && smsSettings.DefaultProviderName == AzureSmsProvider.TechnicalName) + { + await _notifier.WarningAsync(H["You have successfully disabled the default SMS provider. The SMS service is now disable and will remain disabled until you designate a new default provider."]); + + smsSettings.DefaultProviderName = null; + + site.Put(smsSettings); + } + + settings.IsEnabled = false; + } + else + { + settings.IsEnabled = true; + + if (string.IsNullOrWhiteSpace(model.ConnectionString)) + { + context.Updater.ModelState.AddModelError(Prefix, nameof(model.ConnectionString), S["ConnectionString requires a value."]); + } + + if (string.IsNullOrWhiteSpace(model.PhoneNumber)) + { + context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Phone number requires a value."]); + } + else if (!_phoneFormatValidator.IsValid(model.PhoneNumber)) + { + context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Please provide a valid phone number."]); + } + + // Has change should be evaluated before updating the value. + hasChanges |= settings.ConnectionString != model.ConnectionString; + hasChanges |= settings.PhoneNumber != model.PhoneNumber; + + settings.ConnectionString = model.ConnectionString; + settings.PhoneNumber = model.PhoneNumber; + } + + if (context.Updater.ModelState.IsValid && hasChanges) + { + await _shellHost.ReleaseShellContextAsync(_shellSettings); + } + } + + return Edit(settings); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs new file mode 100644 index 00000000000..630d854e045 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs @@ -0,0 +1,92 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using OrchardCore.DisplayManagement.Entities; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.Views; +using OrchardCore.Environment.Shell; +using OrchardCore.Mvc.ModelBinding; +using OrchardCore.Settings; +using OrchardCore.Sms.Azure.ViewModels; + +namespace OrchardCore.Sms.Azure.Drivers; + +public class SmsSettingsDisplayDriver : SectionDisplayDriver +{ + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IAuthorizationService _authorizationService; + private readonly IShellHost _shellHost; + private readonly ShellSettings _shellSettings; + + protected IStringLocalizer S; + + private readonly SmsProviderOptions _smsProviderOptions; + + public SmsSettingsDisplayDriver( + IHttpContextAccessor httpContextAccessor, + IAuthorizationService authorizationService, + IShellHost shellHost, + IOptions smsProviders, + ShellSettings shellSettings, + IStringLocalizer stringLocalizer) + { + _httpContextAccessor = httpContextAccessor; + _authorizationService = authorizationService; + _shellHost = shellHost; + _smsProviderOptions = smsProviders.Value; + _shellSettings = shellSettings; + S = stringLocalizer; + } + + public override IDisplayResult Edit(SmsSettings settings) + => Initialize("SmsSettings_Edit", model => + { + model.DefaultProvider = settings.DefaultProviderName; + model.Providers = _smsProviderOptions.Providers + .Where(entry => entry.Value.IsEnabled) + .Select(entry => new SelectListItem(entry.Key, entry.Key)) + .OrderBy(item => item.Text) + .ToArray(); + + }).Location("Content:1#Providers") + .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) + .OnGroup(SmsSettings.GroupId); + + public override async Task UpdateAsync(SmsSettings settings, BuildEditorContext context) + { + var user = _httpContextAccessor.HttpContext?.User; + + if (!context.GroupId.Equals(SmsSettings.GroupId, StringComparison.OrdinalIgnoreCase) + || !await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) + { + return null; + } + + var model = new SmsSettingsViewModel(); + + if (await context.Updater.TryUpdateModelAsync(model, Prefix)) + { + if (string.IsNullOrEmpty(model.DefaultProvider)) + { + context.Updater.ModelState.AddModelError(Prefix, nameof(model.DefaultProvider), S["You must select a default provider."]); + } + else + { + if (settings.DefaultProviderName != model.DefaultProvider) + { + settings.DefaultProviderName = model.DefaultProvider; + + await _shellHost.ReleaseShellContextAsync(_shellSettings); + } + } + } + + return Edit(settings); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs new file mode 100644 index 00000000000..b95a6da6dff --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs @@ -0,0 +1,69 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.Localization; +using OrchardCore.DisplayManagement.ModelBinding; +using OrchardCore.DisplayManagement.Views; +using OrchardCore.Liquid; +using OrchardCore.Mvc.ModelBinding; +using OrchardCore.Sms.Azure.Activities; +using OrchardCore.Sms.Azure.ViewModels; +using OrchardCore.Workflows.Display; +using OrchardCore.Workflows.Models; + +namespace OrchardCore.Sms.Azure.Drivers; + +public class SmsTaskDisplayDriver : ActivityDisplayDriver +{ + private readonly IPhoneFormatValidator _phoneFormatValidator; + private readonly ILiquidTemplateManager _liquidTemplateManager; + + protected readonly IStringLocalizer S; + + public SmsTaskDisplayDriver( + IPhoneFormatValidator phoneFormatValidator, + ILiquidTemplateManager liquidTemplateManager, + IStringLocalizer stringLocalizer + ) + { + _phoneFormatValidator = phoneFormatValidator; + _liquidTemplateManager = liquidTemplateManager; + S = stringLocalizer; + } + + protected override void EditActivity(SmsTask activity, SmsTaskViewModel model) + { + model.PhoneNumber = activity.PhoneNumber.Expression; + model.Body = activity.Body.Expression; + } + + public async override Task UpdateAsync(SmsTask activity, IUpdateModel updater) + { + var viewModel = new SmsTaskViewModel(); + + if (await updater.TryUpdateModelAsync(viewModel, Prefix)) + { + if (string.IsNullOrWhiteSpace(viewModel.PhoneNumber)) + { + updater.ModelState.AddModelError(Prefix, nameof(viewModel.PhoneNumber), S["Phone number requires a value."]); + } + else if (!_phoneFormatValidator.IsValid(viewModel.PhoneNumber)) + { + updater.ModelState.AddModelError(Prefix, nameof(viewModel.PhoneNumber), S["Invalid phone number used."]); + } + + if (string.IsNullOrWhiteSpace(viewModel.Body)) + { + updater.ModelState.AddModelError(Prefix, nameof(viewModel.Body), S["Message Body requires a value."]); + } + else if (!_liquidTemplateManager.Validate(viewModel.Body, out var bodyErrors)) + { + updater.ModelState.AddModelError(Prefix, nameof(viewModel.Body), string.Join(' ', bodyErrors)); + } + + activity.PhoneNumber = new WorkflowExpression(viewModel.PhoneNumber); + activity.Body = new WorkflowExpression(viewModel.Body); + } + + return Edit(activity); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs new file mode 100644 index 00000000000..79948c20652 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs @@ -0,0 +1,26 @@ +using OrchardCore.Modules.Manifest; + +[assembly: Module( + Author = ManifestConstants.OrchardCoreTeam, + Website = ManifestConstants.OrchardCoreWebsite, + Version = ManifestConstants.OrchardCoreVersion +)] + +[assembly: Feature( + Name = "SMS", + Id = "OrchardCore.Sms", + Description = "Provides settings and services to send SMS messages.", + Category = "SMS" +)] + +[assembly: Feature( + Name = "SMS Notifications", + Id = "OrchardCore.Notifications.Sms", + Description = "Provides a way to send SMS notifications to users.", + Category = "Notifications", + Dependencies = + [ + "OrchardCore.Notifications", + "OrchardCore.Sms", + ] +)] diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSettings.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSettings.cs new file mode 100644 index 00000000000..b2477b83cac --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSettings.cs @@ -0,0 +1,10 @@ +namespace OrchardCore.Sms.Azure.Models; + +public class AzureSettings +{ + public bool IsEnabled { get; set; } + + public string ConnectionString { get; set; } + + public string PhoneNumber { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj new file mode 100644 index 00000000000..2712a4525ca --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj @@ -0,0 +1,31 @@ + + + + true + + OrchardCore Sms + + $(OCCMSDescription) + + The SMS module provides a way to send SMS messages. + + $(PackageTags) OrchardCoreCMS + + + + + + + + + + + + + + + + + + + diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs new file mode 100644 index 00000000000..f1f7cdc37d5 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Azure.Communication.Sms; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using OrchardCore.Settings; +using OrchardCore.Sms.Azure.Models; + +namespace OrchardCore.Sms.Azure.Services; + +public class AzureSmsProvider : ISmsProvider +{ + private readonly ISiteService _siteService; + private readonly IDataProtectionProvider _dataProtectionProvider; + private readonly ILogger _logger; + + private AzureSettings _settings; + + protected readonly IStringLocalizer S; + + public const string TechnicalName = "Azure"; + + public const string ProtectorName = "Azure"; + + public LocalizedString Name => S["Azure"]; + + public AzureSmsProvider( + ISiteService siteService, + IDataProtectionProvider dataProtectionProvider, + ILogger logger, + IStringLocalizer stringLocalizer) + { + _siteService = siteService; + _dataProtectionProvider = dataProtectionProvider; + _logger = logger; + S = stringLocalizer; + } + + public async Task SendAsync(SmsMessage message) + { + ArgumentNullException.ThrowIfNull(message); + + if (string.IsNullOrEmpty(message.To)) + { + throw new ArgumentException("A phone number is required in order to send a message."); + } + + if (string.IsNullOrEmpty(message.Body)) + { + throw new ArgumentException("A message body is required in order to send a message."); + } + + try + { + var settings = await GetSettingsAsync(); + var data = new List> + { + new ("From", settings.PhoneNumber), + new ("To", message.To), + new ("Body", message.Body), + }; + + var client = new SmsClient(settings.ConnectionString); + var response = await client.SendAsync(settings.PhoneNumber, message.To, message.Body); + + if (response.Value.Successful) + { + return SmsResult.Success; + } + else + { + return SmsResult.Failed(S["SMS message was not send."]); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Azure service was unable to send SMS messages."); + + return SmsResult.Failed(S["SMS message was not send. Error: {0}", ex.Message]); + } + } + + private async Task GetSettingsAsync() + { + if (_settings == null) + { + var settings = (await _siteService.GetSiteSettingsAsync()).As(); + + var protector = _dataProtectionProvider.CreateProtector(ProtectorName); + + _settings = new AzureSettings + { + ConnectionString = settings.ConnectionString == null ? null : protector.Unprotect(settings.ConnectionString), + PhoneNumber = settings.PhoneNumber + }; + } + + return _settings; + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissionProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissionProvider.cs new file mode 100644 index 00000000000..a3f65d82404 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissionProvider.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using OrchardCore.Security.Permissions; + +namespace OrchardCore.Sms.Azure; + +public class SmsPermissionProvider : IPermissionProvider +{ + public static readonly Permission ManageSmsSettings = SmsPermissions.ManageSmsSettings; + + private readonly IEnumerable _allPermissions = + [ + ManageSmsSettings, + ]; + + public Task> GetPermissionsAsync() + => Task.FromResult(_allPermissions); + + public IEnumerable GetDefaultStereotypes() => + [ + new PermissionStereotype + { + Name = "Administrator", + Permissions = _allPermissions, + }, + ]; +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs new file mode 100644 index 00000000000..e88ec15476e --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs @@ -0,0 +1,8 @@ +using OrchardCore.Security.Permissions; + +namespace OrchardCore.Sms.Azure; + +public class SmsPermissions +{ + public static readonly Permission ManageSmsSettings = new("ManageSmsSettings", "Manage SMS Settings"); +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs new file mode 100644 index 00000000000..35eefa83b57 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -0,0 +1,60 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.Modules; +using OrchardCore.Navigation; +using OrchardCore.Notifications; +using OrchardCore.Security.Permissions; +using OrchardCore.Settings; +using OrchardCore.Sms.Azure.Activities; +using OrchardCore.Sms.Azure.Drivers; +using OrchardCore.Sms.Services; +using OrchardCore.Workflows.Helpers; + +namespace OrchardCore.Sms.Azure; + +public class Startup : StartupBase +{ + private readonly IHostEnvironment _hostEnvironment; + + public Startup(IHostEnvironment hostEnvironment) + { + _hostEnvironment = hostEnvironment; + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddSmsServices(); + services.AddPhoneFormatValidator(); + + if (_hostEnvironment.IsDevelopment()) + { + services.AddLogSmsProvider(); + } + + services.AddTwilioSmsProvider() + .AddScoped, AzureSettingsDisplayDriver>(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped, SmsSettingsDisplayDriver>(); + } +} + +[Feature("OrchardCore.Notifications.Sms")] +public class NotificationsStartup : StartupBase +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddScoped(); + } +} + +[RequireFeatures("OrchardCore.Workflows")] +public class WorkflowsStartup : StartupBase +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddActivity(); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs new file mode 100644 index 00000000000..fe82ff10b39 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs @@ -0,0 +1,10 @@ +namespace OrchardCore.Sms.Azure.ViewModels; + +public class AzureSettingsViewModel : SmsSettingsBaseViewModel +{ + public bool IsEnabled { get; set; } + + public string ConnectionString { get; set; } + + public string PhoneNumber { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs new file mode 100644 index 00000000000..a98ab23a336 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs @@ -0,0 +1,6 @@ +namespace OrchardCore.Sms.Azure.ViewModels; + +public class SmsSettingsBaseViewModel +{ + public string DefaultProvider { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs new file mode 100644 index 00000000000..086f601b03a --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace OrchardCore.Sms.Azure.ViewModels; + +public class SmsSettingsViewModel : SmsSettingsBaseViewModel +{ + [BindNever] + public SelectListItem[] Providers { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTaskViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTaskViewModel.cs new file mode 100644 index 00000000000..8e7661a9646 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTaskViewModel.cs @@ -0,0 +1,8 @@ +namespace OrchardCore.Sms.Azure.ViewModels; + +public class SmsTaskViewModel +{ + public string PhoneNumber { get; set; } + + public string Body { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs new file mode 100644 index 00000000000..d3778587aea --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace OrchardCore.Sms.Azure.ViewModels; + +public class SmsTestViewModel +{ + [Required] + public string Provider { get; set; } + + [Required] + public string PhoneNumber { get; set; } + + [BindNever] + public IList Providers { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml new file mode 100644 index 00000000000..803ac540110 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml @@ -0,0 +1,40 @@ +@using OrchardCore +@using OrchardCore.Sms.ViewModels + +@model SmsTestViewModel + +@if (Model.Providers == null || Model.Providers.Count == 0) +{ + + + return; +} + +
+ +
+ +
+ +
+
+ +
+ +
+ + @T["Phone number must include a country code. For example, +1 for United States."] +
+
+ +
+
+ +
+
+ +
diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml new file mode 100644 index 00000000000..74565790710 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml @@ -0,0 +1,35 @@ +@using OrchardCore.Sms.Azure.Services +@using OrchardCore.Sms.Azure.ViewModels +@using OrchardCore.Sms + +@model AzureSettingsViewModel + +
+
+ + +
+
+ +
+ +

@T["Azure Account Info"]

+ +
+ + + + @if (Model.ConnectionString) + { + @T["Connection String was securely saved. Enter a new value if you wish to replace the existing secret."] + } +
+ +
+ + + + @T["Phone number must include a country code. For example, +1 for United States."] +
+ +
diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml new file mode 100644 index 00000000000..5ed5b7fc91d --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml @@ -0,0 +1,12 @@ +@using OrchardCore.Workflows.ViewModels +@using OrchardCore.Sms.Activities +@using OrchardCore.Workflows.Helpers + +@model ActivityViewModel + +
+

+ @Model.Activity.GetTitleOrDefault(() => T["Send SMS"]) +

+
+@Model.Activity.Body diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml new file mode 100644 index 00000000000..d16da5683ef --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml @@ -0,0 +1,35 @@ +@using OrchardCore.Sms.ViewModels + +@model SmsTaskViewModel + +
+ + + + @T["Phone number must include a country code. For example, +1 for United States."] +
+ +
+ + + @T["The body of the SMS message. With Liquid support."] +
+ + + + + + + + + + diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml new file mode 100644 index 00000000000..6b19ed47884 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml @@ -0,0 +1,4 @@ +

+ @T["Send SMS"] +

+

@T["Send an SMS message."]

diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml new file mode 100644 index 00000000000..fadfbabe7a8 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml @@ -0,0 +1,4 @@ + + + +@T["SMS"] diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml new file mode 100644 index 00000000000..8591efef847 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml @@ -0,0 +1,11 @@ +@using OrchardCore.Sms.ViewModels + +@model SmsSettingsViewModel + +
+ + + +
diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/_ViewImports.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/_ViewImports.cshtml new file mode 100644 index 00000000000..252fd654bb8 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/_ViewImports.cshtml @@ -0,0 +1,5 @@ +@inherits OrchardCore.DisplayManagement.Razor.RazorPage + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, OrchardCore.DisplayManagement +@addTagHelper *, OrchardCore.ResourceManagement From 588a0fbe84f4fa2b022d3a688230f581dfe7712f Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Sep 2024 18:35:33 +0300 Subject: [PATCH 02/33] PackageManagement -> PackageVersion --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 32fcdd399d0..f433d8e3de8 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,7 +15,7 @@ - + From 2c7bf82d8da55261eeeaa6ccc0ff3fbb0d16b4be Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Sep 2024 20:07:23 +0300 Subject: [PATCH 03/33] Update the APIs --- .../Activities/SmsTask.cs | 68 ---------- .../OrchardCore.Sms.Azure/AdminMenu.cs | 54 -------- ...vider.cs => AzureSmsPermissionProvider.cs} | 9 +- .../AzureSmsPermissions.cs | 8 ++ .../Controllers/AdminController.cs | 114 ---------------- .../Drivers/AzureSettingsDisplayDriver.cs | 124 +++++++++--------- .../Drivers/SmsSettingsDisplayDriver.cs | 92 ------------- .../Drivers/SmsTaskDisplayDriver.cs | 69 ---------- .../OrchardCore.Sms.Azure/Manifest.cs | 18 +-- .../{AzureSettings.cs => AzureSmsSettings.cs} | 2 +- .../OrchardCore.Sms.Azure.csproj | 5 +- .../Services/AzureSmsProvider.cs | 8 +- .../OrchardCore.Sms.Azure/SmsPermissions.cs | 8 -- .../OrchardCore.Sms.Azure/Startup.cs | 27 +--- .../ViewModels/AzureSettingsViewModel.cs | 7 + ...kViewModel.cs => AzureSmsTaskViewModel.cs} | 2 +- .../ViewModels/SmsSettingsBaseViewModel.cs | 6 - .../ViewModels/SmsSettingsViewModel.cs | 10 -- .../ViewModels/SmsTestViewModel.cs | 18 --- .../Views/Admin/Test.cshtml | 40 ------ .../Views/AzureSettings.Edit.cshtml | 2 +- .../Views/Items/SmsTask.Fields.Design.cshtml | 12 -- .../Views/Items/SmsTask.Fields.Edit.cshtml | 35 ----- .../Items/SmsTask.Fields.Thumbnail.cshtml | 4 - .../Views/NavigationItemText-sms.Id.cshtml | 4 - .../Views/SmsSettings.Edit.cshtml | 11 -- 26 files changed, 92 insertions(+), 665 deletions(-) delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs rename src/OrchardCore.Modules/OrchardCore.Sms.Azure/{SmsPermissionProvider.cs => AzureSmsPermissionProvider.cs} (55%) create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs rename src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/{AzureSettings.cs => AzureSmsSettings.cs} (85%) delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs rename src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/{SmsTaskViewModel.cs => AzureSmsTaskViewModel.cs} (78%) delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs deleted file mode 100644 index 0681c89930c..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Activities/SmsTask.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Extensions.Localization; -using OrchardCore.Workflows.Abstractions.Models; -using OrchardCore.Workflows.Activities; -using OrchardCore.Workflows.Models; -using OrchardCore.Workflows.Services; - -namespace OrchardCore.Sms.Azure.Activities; - -public class SmsTask : TaskActivity -{ - private readonly ISmsService _smsService; - private readonly IWorkflowExpressionEvaluator _expressionEvaluator; - protected readonly IStringLocalizer S; - - public SmsTask( - ISmsService smsService, - IWorkflowExpressionEvaluator expressionEvaluator, - IStringLocalizer stringLocalizer - ) - { - _smsService = smsService; - _expressionEvaluator = expressionEvaluator; - S = stringLocalizer; - } - - public override LocalizedString DisplayText => S["SMS Task"]; - - public override LocalizedString Category => S["Messaging"]; - - public WorkflowExpression PhoneNumber - { - get => GetProperty(() => new WorkflowExpression()); - set => SetProperty(value); - } - - public WorkflowExpression Body - { - get => GetProperty(() => new WorkflowExpression()); - set => SetProperty(value); - } - - public override IEnumerable GetPossibleOutcomes(WorkflowExecutionContext workflowContext, ActivityContext activityContext) - { - return Outcomes(S["Done"], S["Failed"]); - } - - public override async Task ExecuteAsync(WorkflowExecutionContext workflowContext, ActivityContext activityContext) - { - var message = new SmsMessage - { - To = await _expressionEvaluator.EvaluateAsync(PhoneNumber, workflowContext, null), - Body = await _expressionEvaluator.EvaluateAsync(Body, workflowContext, null), - }; - - var result = await _smsService.SendAsync(message); - - workflowContext.LastResult = result; - - if (result.Succeeded) - { - return Outcomes("Done"); - } - - return Outcomes("Failed"); - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs deleted file mode 100644 index 22bc4290c6c..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AdminMenu.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Localization; -using OrchardCore.Mvc.Core.Utilities; -using OrchardCore.Navigation; -using OrchardCore.Sms.Azure.Controllers; - -namespace OrchardCore.Sms.Azure; - -public class AdminMenu : INavigationProvider -{ - private static readonly RouteValueDictionary _routeValues = new() - { - { "area", "OrchardCore.Settings" }, - { "groupId", SmsSettings.GroupId }, - }; - - protected readonly IStringLocalizer S; - - public AdminMenu(IStringLocalizer stringLocalizer) - { - S = stringLocalizer; - } - - public Task BuildNavigationAsync(string name, NavigationBuilder builder) - { - if (!NavigationHelper.IsAdminMenu(name)) - { - return Task.CompletedTask; - } - - builder - .Add(S["Configuration"], configuration => configuration - .Add(S["Settings"], settings => settings - .Add(S["SMS"], S["SMS"].PrefixPosition(), sms => sms - .AddClass("sms") - .Id("sms") - .Action("Index", "Admin", _routeValues) - .Permission(SmsPermissions.ManageSmsSettings) - .LocalNav() - ) - .Add(S["SMS Test"], S["SMS Test"].PrefixPosition(), sms => sms - .AddClass("smstest") - .Id("smstest") - .Action(nameof(AdminController.Test), typeof(AdminController).ControllerName(), "OrchardCore.Sms") - .Permission(SmsPermissions.ManageSmsSettings) - .LocalNav() - ) - ) - ); - - return Task.CompletedTask; - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissionProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs similarity index 55% rename from src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissionProvider.cs rename to src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs index a3f65d82404..78f5d442590 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissionProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs @@ -1,20 +1,17 @@ -using System.Collections.Generic; -using System.Threading.Tasks; using OrchardCore.Security.Permissions; namespace OrchardCore.Sms.Azure; -public class SmsPermissionProvider : IPermissionProvider +public class AzureSmsPermissionProvider : IPermissionProvider { - public static readonly Permission ManageSmsSettings = SmsPermissions.ManageSmsSettings; + public static readonly Permission ManageSmsSettings = AzureSmsPermissions.ManageAzureSmsSettings; private readonly IEnumerable _allPermissions = [ ManageSmsSettings, ]; - public Task> GetPermissionsAsync() - => Task.FromResult(_allPermissions); + public Task> GetPermissionsAsync() => Task.FromResult(_allPermissions); public IEnumerable GetDefaultStereotypes() => [ diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs new file mode 100644 index 00000000000..8e661b04b49 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs @@ -0,0 +1,8 @@ +using OrchardCore.Security.Permissions; + +namespace OrchardCore.Sms.Azure; + +public class AzureSmsPermissions +{ + public static readonly Permission ManageAzureSmsSettings = new("ManageAzureSmsSettings", "Manage Azure SMS Settings"); +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs deleted file mode 100644 index 531619f417d..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Controllers/AdminController.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Localization; -using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Options; -using OrchardCore.Admin; -using OrchardCore.DisplayManagement.Notify; -using OrchardCore.Sms.Azure.ViewModels; - -namespace OrchardCore.Sms.Azure.Controllers; - -public class AdminController : Controller -{ - private readonly SmsProviderOptions _smsProviderOptions; - private readonly IPhoneFormatValidator _phoneFormatValidator; - private readonly INotifier _notifier; - private readonly IAuthorizationService _authorizationService; - private readonly ISmsProviderResolver _smsProviderResolver; - - protected readonly IHtmlLocalizer H; - protected readonly IStringLocalizer S; - - public AdminController( - IOptions smsProviderOptions, - IPhoneFormatValidator phoneFormatValidator, - ISmsProviderResolver smsProviderResolver, - INotifier notifier, - IAuthorizationService authorizationService, - IHtmlLocalizer htmlLocalizer, - IStringLocalizer stringLocalizer) - { - _smsProviderOptions = smsProviderOptions.Value; - _phoneFormatValidator = phoneFormatValidator; - _smsProviderResolver = smsProviderResolver; - _notifier = notifier; - _authorizationService = authorizationService; - H = htmlLocalizer; - S = stringLocalizer; - } - - [Admin("sms/test", "SmsProviderTest")] - public async Task Test() - { - if (!await _authorizationService.AuthorizeAsync(User, SmsPermissions.ManageSmsSettings)) - { - return Forbid(); - } - - var model = new SmsTestViewModel(); - - PopulateModel(model); - - return View(model); - } - - [HttpPost] - [ValidateAntiForgeryToken] - public async Task Test(SmsTestViewModel model) - { - if (!await _authorizationService.AuthorizeAsync(User, SmsPermissions.ManageSmsSettings)) - { - return Forbid(); - } - - if (ModelState.IsValid) - { - var provider = await _smsProviderResolver.GetAsync(model.Provider); - - if (provider is null) - { - ModelState.AddModelError(nameof(model.Provider), S["Please select a valid provider."]); - } - else if (!_phoneFormatValidator.IsValid(model.PhoneNumber)) - { - ModelState.AddModelError(nameof(model.PhoneNumber), S["Please provide a valid phone number."]); - } - else - { - var result = await provider.SendAsync(new SmsMessage() - { - To = model.PhoneNumber, - Body = S["This is a test SMS message."] - }); - - if (result.Succeeded) - { - await _notifier.SuccessAsync(H["The test SMS message has been successfully sent."]); - - return RedirectToAction(nameof(Test)); - } - else - { - await _notifier.ErrorAsync(H["The test SMS message failed to send."]); - } - } - } - - PopulateModel(model); - - return View(model); - } - - private void PopulateModel(SmsTestViewModel model) - { - model.Providers = _smsProviderOptions.Providers - .Where(entry => entry.Value.IsEnabled) - .Select(entry => new SelectListItem(entry.Key, entry.Key)) - .OrderBy(item => item.Text) - .ToArray(); - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index 6b62289dbcf..9bfd898d5c9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -1,5 +1,3 @@ -using System; -using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; @@ -8,8 +6,6 @@ using Microsoft.Extensions.Localization; using OrchardCore.DisplayManagement.Entities; using OrchardCore.DisplayManagement.Handlers; -using OrchardCore.DisplayManagement.ModelBinding; -using OrchardCore.DisplayManagement.Notify; using OrchardCore.DisplayManagement.Views; using OrchardCore.Entities; using OrchardCore.Environment.Shell; @@ -21,116 +17,118 @@ namespace OrchardCore.Sms.Azure.Drivers; -public class AzureSettingsDisplayDriver : SectionDisplayDriver +public sealed class AzureSettingsDisplayDriver : SiteDisplayDriver { + private readonly IShellReleaseManager _shellReleaseManager; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAuthorizationService _authorizationService; private readonly IPhoneFormatValidator _phoneFormatValidator; private readonly IDataProtectionProvider _dataProtectionProvider; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; - private readonly INotifier _notifier; - protected readonly IHtmlLocalizer H; - protected readonly IStringLocalizer S; + internal readonly IHtmlLocalizer H; + internal readonly IStringLocalizer S; + + protected override string SettingsGroupId => SmsSettings.GroupId; public AzureSettingsDisplayDriver( + IShellReleaseManager shellReleaseManager, IHttpContextAccessor httpContextAccessor, IAuthorizationService authorizationService, IPhoneFormatValidator phoneFormatValidator, IDataProtectionProvider dataProtectionProvider, - IShellHost shellHost, - ShellSettings shellSettings, - INotifier notifier, IHtmlLocalizer htmlLocalizer, IStringLocalizer stringLocalizer) { + _shellReleaseManager = shellReleaseManager; _httpContextAccessor = httpContextAccessor; _authorizationService = authorizationService; _phoneFormatValidator = phoneFormatValidator; _dataProtectionProvider = dataProtectionProvider; - _shellHost = shellHost; - _shellSettings = shellSettings; - _notifier = notifier; H = htmlLocalizer; S = stringLocalizer; } - public override IDisplayResult Edit(AzureSettings settings) + public override IDisplayResult Edit(ISite site, AzureSmsSettings settings, BuildEditorContext c) { - return Initialize("TwilioSettings_Edit", model => + return Initialize("AzureSettings_Edit", model => { model.IsEnabled = settings.IsEnabled; - model.ConnectionString = settings.ConnectionString; model.PhoneNumber = settings.PhoneNumber; - }).Location("Content:5#Twilio") - .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) - .OnGroup(SmsSettings.GroupId); + model.ConnectionString = settings.ConnectionString; + }).Location("Content:5#Azure") + .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, AzureSmsPermissions.ManageAzureSmsSettings)) + .OnGroup(SettingsGroupId); } - public override async Task UpdateAsync(ISite site, AzureSettings settings, IUpdateModel updater, BuildEditorContext context) + public override async Task UpdateAsync(ISite site, AzureSmsSettings settings, UpdateEditorContext context) { var user = _httpContextAccessor.HttpContext?.User; - if (!context.GroupId.Equals(SmsSettings.GroupId, StringComparison.OrdinalIgnoreCase) - || !await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) + if (!await _authorizationService.AuthorizeAsync(user, AzureSmsPermissions.ManageAzureSmsSettings)) { return null; } var model = new AzureSettingsViewModel(); - if (await context.Updater.TryUpdateModelAsync(model, Prefix)) + await context.Updater.TryUpdateModelAsync(model, Prefix); + + var hasChanges = settings.IsEnabled != model.IsEnabled; + if (!model.IsEnabled) { - var hasChanges = settings.IsEnabled != model.IsEnabled; + var smsSettings = site.As(); - if (!model.IsEnabled) + if (hasChanges && smsSettings.DefaultProviderName == AzureSmsProvider.TechnicalName) { - var smsSettings = site.As(); - - if (hasChanges && smsSettings.DefaultProviderName == AzureSmsProvider.TechnicalName) - { - await _notifier.WarningAsync(H["You have successfully disabled the default SMS provider. The SMS service is now disable and will remain disabled until you designate a new default provider."]); + smsSettings.DefaultProviderName = null; - smsSettings.DefaultProviderName = null; + site.Put(smsSettings); + } - site.Put(smsSettings); - } + settings.IsEnabled = false; + } + else + { + settings.IsEnabled = true; - settings.IsEnabled = false; + if (string.IsNullOrWhiteSpace(model.PhoneNumber)) + { + context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Invalid Phone number."]); + } + else if (!_phoneFormatValidator.IsValid(model.PhoneNumber)) + { + context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Invalid phone number."]); } - else + + if (string.IsNullOrWhiteSpace(model.ConnectionString)) { - settings.IsEnabled = true; - - if (string.IsNullOrWhiteSpace(model.ConnectionString)) - { - context.Updater.ModelState.AddModelError(Prefix, nameof(model.ConnectionString), S["ConnectionString requires a value."]); - } - - if (string.IsNullOrWhiteSpace(model.PhoneNumber)) - { - context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Phone number requires a value."]); - } - else if (!_phoneFormatValidator.IsValid(model.PhoneNumber)) - { - context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Please provide a valid phone number."]); - } - - // Has change should be evaluated before updating the value. - hasChanges |= settings.ConnectionString != model.ConnectionString; - hasChanges |= settings.PhoneNumber != model.PhoneNumber; - - settings.ConnectionString = model.ConnectionString; - settings.PhoneNumber = model.PhoneNumber; + context.Updater.ModelState.AddModelError(Prefix, nameof(model.ConnectionString), S["The ConnectionString is required."]); } - if (context.Updater.ModelState.IsValid && hasChanges) + // Has change should be evaluated before updating the value. + hasChanges |= settings.PhoneNumber != model.PhoneNumber; + hasChanges |= settings.ConnectionString != model.ConnectionString; + + settings.PhoneNumber = model.PhoneNumber; + settings.ConnectionString = model.ConnectionString; + + if (!string.IsNullOrWhiteSpace(model.ConnectionString)) { - await _shellHost.ReleaseShellContextAsync(_shellSettings); + var protector = _dataProtectionProvider.CreateProtector(AzureSmsProvider.ProtectorName); + + var protectedToken = protector.Protect(model.ConnectionString); + + hasChanges |= settings.ConnectionString != protectedToken; + + settings.ConnectionString = protectedToken; } } - return Edit(settings); + if (hasChanges) + { + _shellReleaseManager.RequestRelease(); + } + + return Edit(site, settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs deleted file mode 100644 index 630d854e045..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsSettingsDisplayDriver.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Options; -using OrchardCore.DisplayManagement.Entities; -using OrchardCore.DisplayManagement.Handlers; -using OrchardCore.DisplayManagement.Views; -using OrchardCore.Environment.Shell; -using OrchardCore.Mvc.ModelBinding; -using OrchardCore.Settings; -using OrchardCore.Sms.Azure.ViewModels; - -namespace OrchardCore.Sms.Azure.Drivers; - -public class SmsSettingsDisplayDriver : SectionDisplayDriver -{ - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IAuthorizationService _authorizationService; - private readonly IShellHost _shellHost; - private readonly ShellSettings _shellSettings; - - protected IStringLocalizer S; - - private readonly SmsProviderOptions _smsProviderOptions; - - public SmsSettingsDisplayDriver( - IHttpContextAccessor httpContextAccessor, - IAuthorizationService authorizationService, - IShellHost shellHost, - IOptions smsProviders, - ShellSettings shellSettings, - IStringLocalizer stringLocalizer) - { - _httpContextAccessor = httpContextAccessor; - _authorizationService = authorizationService; - _shellHost = shellHost; - _smsProviderOptions = smsProviders.Value; - _shellSettings = shellSettings; - S = stringLocalizer; - } - - public override IDisplayResult Edit(SmsSettings settings) - => Initialize("SmsSettings_Edit", model => - { - model.DefaultProvider = settings.DefaultProviderName; - model.Providers = _smsProviderOptions.Providers - .Where(entry => entry.Value.IsEnabled) - .Select(entry => new SelectListItem(entry.Key, entry.Key)) - .OrderBy(item => item.Text) - .ToArray(); - - }).Location("Content:1#Providers") - .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) - .OnGroup(SmsSettings.GroupId); - - public override async Task UpdateAsync(SmsSettings settings, BuildEditorContext context) - { - var user = _httpContextAccessor.HttpContext?.User; - - if (!context.GroupId.Equals(SmsSettings.GroupId, StringComparison.OrdinalIgnoreCase) - || !await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) - { - return null; - } - - var model = new SmsSettingsViewModel(); - - if (await context.Updater.TryUpdateModelAsync(model, Prefix)) - { - if (string.IsNullOrEmpty(model.DefaultProvider)) - { - context.Updater.ModelState.AddModelError(Prefix, nameof(model.DefaultProvider), S["You must select a default provider."]); - } - else - { - if (settings.DefaultProviderName != model.DefaultProvider) - { - settings.DefaultProviderName = model.DefaultProvider; - - await _shellHost.ReleaseShellContextAsync(_shellSettings); - } - } - } - - return Edit(settings); - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs deleted file mode 100644 index b95a6da6dff..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/SmsTaskDisplayDriver.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.Extensions.Localization; -using OrchardCore.DisplayManagement.ModelBinding; -using OrchardCore.DisplayManagement.Views; -using OrchardCore.Liquid; -using OrchardCore.Mvc.ModelBinding; -using OrchardCore.Sms.Azure.Activities; -using OrchardCore.Sms.Azure.ViewModels; -using OrchardCore.Workflows.Display; -using OrchardCore.Workflows.Models; - -namespace OrchardCore.Sms.Azure.Drivers; - -public class SmsTaskDisplayDriver : ActivityDisplayDriver -{ - private readonly IPhoneFormatValidator _phoneFormatValidator; - private readonly ILiquidTemplateManager _liquidTemplateManager; - - protected readonly IStringLocalizer S; - - public SmsTaskDisplayDriver( - IPhoneFormatValidator phoneFormatValidator, - ILiquidTemplateManager liquidTemplateManager, - IStringLocalizer stringLocalizer - ) - { - _phoneFormatValidator = phoneFormatValidator; - _liquidTemplateManager = liquidTemplateManager; - S = stringLocalizer; - } - - protected override void EditActivity(SmsTask activity, SmsTaskViewModel model) - { - model.PhoneNumber = activity.PhoneNumber.Expression; - model.Body = activity.Body.Expression; - } - - public async override Task UpdateAsync(SmsTask activity, IUpdateModel updater) - { - var viewModel = new SmsTaskViewModel(); - - if (await updater.TryUpdateModelAsync(viewModel, Prefix)) - { - if (string.IsNullOrWhiteSpace(viewModel.PhoneNumber)) - { - updater.ModelState.AddModelError(Prefix, nameof(viewModel.PhoneNumber), S["Phone number requires a value."]); - } - else if (!_phoneFormatValidator.IsValid(viewModel.PhoneNumber)) - { - updater.ModelState.AddModelError(Prefix, nameof(viewModel.PhoneNumber), S["Invalid phone number used."]); - } - - if (string.IsNullOrWhiteSpace(viewModel.Body)) - { - updater.ModelState.AddModelError(Prefix, nameof(viewModel.Body), S["Message Body requires a value."]); - } - else if (!_liquidTemplateManager.Validate(viewModel.Body, out var bodyErrors)) - { - updater.ModelState.AddModelError(Prefix, nameof(viewModel.Body), string.Join(' ', bodyErrors)); - } - - activity.PhoneNumber = new WorkflowExpression(viewModel.PhoneNumber); - activity.Body = new WorkflowExpression(viewModel.Body); - } - - return Edit(activity); - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs index 79948c20652..8ae08875efd 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs @@ -7,20 +7,8 @@ )] [assembly: Feature( - Name = "SMS", - Id = "OrchardCore.Sms", - Description = "Provides settings and services to send SMS messages.", + Name = "Azure SMS", + Id = "OrchardCore.Sms.Azure", + Description = "Provides settings and services to send SMS messages using Azure Communication Services (ACS).", Category = "SMS" )] - -[assembly: Feature( - Name = "SMS Notifications", - Id = "OrchardCore.Notifications.Sms", - Description = "Provides a way to send SMS notifications to users.", - Category = "Notifications", - Dependencies = - [ - "OrchardCore.Notifications", - "OrchardCore.Sms", - ] -)] diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSettings.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsSettings.cs similarity index 85% rename from src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSettings.cs rename to src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsSettings.cs index b2477b83cac..2f5b4cfdd01 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSettings.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsSettings.cs @@ -1,6 +1,6 @@ namespace OrchardCore.Sms.Azure.Models; -public class AzureSettings +public class AzureSmsSettings { public bool IsEnabled { get; set; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj index 2712a4525ca..adbc66284db 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj @@ -7,7 +7,7 @@ $(OCCMSDescription) - The SMS module provides a way to send SMS messages. + The Azure SMS module provides a way to send SMS messages using Azure Communication Services (ACS). $(PackageTags) OrchardCoreCMS @@ -23,9 +23,8 @@ - - + diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs index f1f7cdc37d5..a4343350c05 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -16,7 +16,7 @@ public class AzureSmsProvider : ISmsProvider private readonly IDataProtectionProvider _dataProtectionProvider; private readonly ILogger _logger; - private AzureSettings _settings; + private AzureSmsSettings _settings; protected readonly IStringLocalizer S; @@ -82,15 +82,15 @@ public async Task SendAsync(SmsMessage message) } } - private async Task GetSettingsAsync() + private async Task GetSettingsAsync() { if (_settings == null) { - var settings = (await _siteService.GetSiteSettingsAsync()).As(); + var settings = (await _siteService.GetSiteSettingsAsync()).As(); var protector = _dataProtectionProvider.CreateProtector(ProtectorName); - _settings = new AzureSettings + _settings = new AzureSmsSettings { ConnectionString = settings.ConnectionString == null ? null : protector.Unprotect(settings.ConnectionString), PhoneNumber = settings.PhoneNumber diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs deleted file mode 100644 index e88ec15476e..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/SmsPermissions.cs +++ /dev/null @@ -1,8 +0,0 @@ -using OrchardCore.Security.Permissions; - -namespace OrchardCore.Sms.Azure; - -public class SmsPermissions -{ - public static readonly Permission ManageSmsSettings = new("ManageSmsSettings", "Manage SMS Settings"); -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs index 35eefa83b57..ded47cd2ea3 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -2,14 +2,9 @@ using Microsoft.Extensions.Hosting; using OrchardCore.DisplayManagement.Handlers; using OrchardCore.Modules; -using OrchardCore.Navigation; -using OrchardCore.Notifications; using OrchardCore.Security.Permissions; using OrchardCore.Settings; -using OrchardCore.Sms.Azure.Activities; using OrchardCore.Sms.Azure.Drivers; -using OrchardCore.Sms.Services; -using OrchardCore.Workflows.Helpers; namespace OrchardCore.Sms.Azure; @@ -35,26 +30,6 @@ public override void ConfigureServices(IServiceCollection services) services.AddTwilioSmsProvider() .AddScoped, AzureSettingsDisplayDriver>(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped, SmsSettingsDisplayDriver>(); - } -} - -[Feature("OrchardCore.Notifications.Sms")] -public class NotificationsStartup : StartupBase -{ - public override void ConfigureServices(IServiceCollection services) - { - services.AddScoped(); - } -} - -[RequireFeatures("OrchardCore.Workflows")] -public class WorkflowsStartup : StartupBase -{ - public override void ConfigureServices(IServiceCollection services) - { - services.AddActivity(); + services.AddScoped(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs index fe82ff10b39..f31ed32dd1d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs @@ -1,3 +1,6 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding; +using OrchardCore.Sms.ViewModels; + namespace OrchardCore.Sms.Azure.ViewModels; public class AzureSettingsViewModel : SmsSettingsBaseViewModel @@ -7,4 +10,8 @@ public class AzureSettingsViewModel : SmsSettingsBaseViewModel public string ConnectionString { get; set; } public string PhoneNumber { get; set; } + + + [BindNever] + public bool HasConnectionString { get; set; } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTaskViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSmsTaskViewModel.cs similarity index 78% rename from src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTaskViewModel.cs rename to src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSmsTaskViewModel.cs index 8e7661a9646..27aa6f09286 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTaskViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSmsTaskViewModel.cs @@ -1,6 +1,6 @@ namespace OrchardCore.Sms.Azure.ViewModels; -public class SmsTaskViewModel +public class AzureSmsTaskViewModel { public string PhoneNumber { get; set; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs deleted file mode 100644 index a98ab23a336..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsBaseViewModel.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace OrchardCore.Sms.Azure.ViewModels; - -public class SmsSettingsBaseViewModel -{ - public string DefaultProvider { get; set; } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs deleted file mode 100644 index 086f601b03a..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsSettingsViewModel.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.Rendering; - -namespace OrchardCore.Sms.Azure.ViewModels; - -public class SmsSettingsViewModel : SmsSettingsBaseViewModel -{ - [BindNever] - public SelectListItem[] Providers { get; set; } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs deleted file mode 100644 index d3778587aea..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/SmsTestViewModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.Rendering; - -namespace OrchardCore.Sms.Azure.ViewModels; - -public class SmsTestViewModel -{ - [Required] - public string Provider { get; set; } - - [Required] - public string PhoneNumber { get; set; } - - [BindNever] - public IList Providers { get; set; } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml deleted file mode 100644 index 803ac540110..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Admin/Test.cshtml +++ /dev/null @@ -1,40 +0,0 @@ -@using OrchardCore -@using OrchardCore.Sms.ViewModels - -@model SmsTestViewModel - -@if (Model.Providers == null || Model.Providers.Count == 0) -{ - - - return; -} - -
- -
- -
- -
-
- -
- -
- - @T["Phone number must include a country code. For example, +1 for United States."] -
-
- -
-
- -
-
- -
diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml index 74565790710..1c70a41363f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml @@ -19,7 +19,7 @@ - @if (Model.ConnectionString) + @if (Model.HasConnectionString) { @T["Connection String was securely saved. Enter a new value if you wish to replace the existing secret."] } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml deleted file mode 100644 index 5ed5b7fc91d..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Design.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@using OrchardCore.Workflows.ViewModels -@using OrchardCore.Sms.Activities -@using OrchardCore.Workflows.Helpers - -@model ActivityViewModel - -
-

- @Model.Activity.GetTitleOrDefault(() => T["Send SMS"]) -

-
-@Model.Activity.Body diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml deleted file mode 100644 index d16da5683ef..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Edit.cshtml +++ /dev/null @@ -1,35 +0,0 @@ -@using OrchardCore.Sms.ViewModels - -@model SmsTaskViewModel - -
- - - - @T["Phone number must include a country code. For example, +1 for United States."] -
- -
- - - @T["The body of the SMS message. With Liquid support."] -
- - - - - - - - - - diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml deleted file mode 100644 index 6b19ed47884..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/Items/SmsTask.Fields.Thumbnail.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -

- @T["Send SMS"] -

-

@T["Send an SMS message."]

diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml deleted file mode 100644 index fadfbabe7a8..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/NavigationItemText-sms.Id.cshtml +++ /dev/null @@ -1,4 +0,0 @@ - - - -@T["SMS"] diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml deleted file mode 100644 index 8591efef847..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/SmsSettings.Edit.cshtml +++ /dev/null @@ -1,11 +0,0 @@ -@using OrchardCore.Sms.ViewModels - -@model SmsSettingsViewModel - -
- - - -
From e358db49892be7fd0640d71024773e20e5bb6945 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Sep 2024 20:15:19 +0300 Subject: [PATCH 04/33] Remove module to module dependency --- .../OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj | 1 - .../ViewModels/SmsSettingsBaseViewModel.cs | 0 .../.template.config/dotnetcli.host.json | 4 ++-- .../.template.config/template.json | 4 ++-- .../.template.config/dotnetcli.host.json | 2 +- .../.template.config/template.json | 4 ++-- .../.template.config/dotnetcli.host.json | 4 ++-- .../.template.config/template.json | 4 ++-- .../.template.config/dotnetcli.host.json | 4 ++-- .../.template.config/template.json | 4 ++-- .../.template.config/template.json | 4 ++-- 11 files changed, 17 insertions(+), 18 deletions(-) rename src/{OrchardCore.Modules/OrchardCore.Sms => OrchardCore/OrchardCore.Sms.Core}/ViewModels/SmsSettingsBaseViewModel.cs (100%) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj index adbc66284db..820748ec57e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj @@ -25,6 +25,5 @@ - diff --git a/src/OrchardCore.Modules/OrchardCore.Sms/ViewModels/SmsSettingsBaseViewModel.cs b/src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs similarity index 100% rename from src/OrchardCore.Modules/OrchardCore.Sms/ViewModels/SmsSettingsBaseViewModel.cs rename to src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json index e1c98deab31..0985e309cd1 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json @@ -12,6 +12,6 @@ }, "usageExamples": [ "--framework net8.0", - "--orchard-version 2.0.0" + "--orchard-version 1.8.3" ] -} +} \ No newline at end of file diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json index 438ab0b5981..32bcc1b3b65 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json @@ -45,7 +45,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.0.0" + "defaultValue": "2.1.0-preview" } }, "sources": [ @@ -76,4 +76,4 @@ "language": "C#", "type": "project" } -} +} \ No newline at end of file diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json index 0139158446a..154ec41ee08 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json @@ -17,6 +17,6 @@ "usageExamples": [ "--framework net8.0", "--logger none", - "--orchard-version 2.0.0" + "--orchard-version 1.8.3" ] } diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json index a72f53be27b..e4304604208 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json @@ -51,7 +51,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.0.0" + "defaultValue": "2.1.0-preview" }, "UseNLog": { "type": "computed", @@ -78,4 +78,4 @@ "language": "C#", "type": "project" } -} +} \ No newline at end of file diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json index e1c98deab31..0985e309cd1 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json @@ -12,6 +12,6 @@ }, "usageExamples": [ "--framework net8.0", - "--orchard-version 2.0.0" + "--orchard-version 1.8.3" ] -} +} \ No newline at end of file diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json index 8b078818009..6e05e3703de 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json @@ -31,7 +31,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.0.0" + "defaultValue": "2.1.0-preview" } }, "sources": [ @@ -43,4 +43,4 @@ "language": "C#", "type": "project" } -} +} \ No newline at end of file diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json index e1c98deab31..0985e309cd1 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json @@ -12,6 +12,6 @@ }, "usageExamples": [ "--framework net8.0", - "--orchard-version 2.0.0" + "--orchard-version 1.8.3" ] -} +} \ No newline at end of file diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json index 1b68b2c47d5..053d07ad0f9 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json @@ -31,7 +31,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.0.0" + "defaultValue": "2.1.0-preview" } }, "sources": [], @@ -39,4 +39,4 @@ "language": "C#", "type": "project" } -} +} \ No newline at end of file diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json index d6ef70ab857..e9842d31fec 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json @@ -37,7 +37,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.0.0" + "defaultValue": "2.1.0-preview" } }, "sources": [ @@ -59,4 +59,4 @@ "language": "C#", "type": "project" } -} +} \ No newline at end of file From 955acaee7dc01bae3bf27b1830cba259ba78fa3c Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Sep 2024 22:18:44 +0300 Subject: [PATCH 05/33] Add project reference --- .../OrchardCore.Application.Cms.Core.Targets.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OrchardCore/OrchardCore.Application.Cms.Core.Targets/OrchardCore.Application.Cms.Core.Targets.csproj b/src/OrchardCore/OrchardCore.Application.Cms.Core.Targets/OrchardCore.Application.Cms.Core.Targets.csproj index 156ba96f7a6..252fde56425 100644 --- a/src/OrchardCore/OrchardCore.Application.Cms.Core.Targets/OrchardCore.Application.Cms.Core.Targets.csproj +++ b/src/OrchardCore/OrchardCore.Application.Cms.Core.Targets/OrchardCore.Application.Cms.Core.Targets.csproj @@ -114,6 +114,7 @@ + From 1b9144222044bfee4a6ec9fb7902cec328159a4e Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Sep 2024 22:18:52 +0300 Subject: [PATCH 06/33] Add unit test --- .../Services/AzureSmsProviderTests.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs new file mode 100644 index 00000000000..1f61d954e66 --- /dev/null +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs @@ -0,0 +1,47 @@ +using OrchardCore.Settings; +using OrchardCore.Sms.Azure.Models; +using OrchardCore.Tests.Utilities; + +namespace OrchardCore.Sms.Azure.Services.Tests; + +public class AzureSmsProviderTests +{ + [Fact(Skip = "Configure the default sender and connection string for SMS Communication Services (ACS) before run this test.")] + public async Task SendSmsShouldSucceed() + { + // Arrange + var siteSettings = GetSiteService(); + var azureSmsProvider = new AzureSmsProvider( + siteSettings, + Mock.Of(), + Mock.Of>(), + Mock.Of>()); + var message = new SmsMessage + { + To = "test@orchardcore.net", + Body = "This is a test message." + }; + + // Act + var result = await azureSmsProvider.SendAsync(message); + + // Assert + Assert.True(result.Succeeded); + } + + private static ISiteService GetSiteService() + { + var azureSmsSettings = new AzureSmsSettings + { + PhoneNumber = "<>", + ConnectionString = "<>" + }; + var siteServiceMock = new Mock(); + + siteServiceMock. + Setup(siteService => siteService.GetSiteSettingsAsync()). + ReturnsAsync(SiteMockHelper.GetSite(azureSmsSettings).Object); + + return siteServiceMock.Object; + } +} From 19824f22e91c3d85f7c3696aa2679638d69beef1 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 14:51:42 +0300 Subject: [PATCH 07/33] Apply suggestions from code review Co-authored-by: Mike Alhayek --- .../AzureSmsPermissionProvider.cs | 5 +++-- .../OrchardCore.Sms.Azure/AzureSmsPermissions.cs | 2 +- .../OrchardCore.Sms.Azure.csproj | 2 +- .../Services/AzureSmsProvider.cs | 11 ++++------- .../OrchardCore.Sms.Azure/Startup.cs | 4 ++-- .../ViewModels/AzureSettingsViewModel.cs | 2 -- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs index 78f5d442590..97924f78df8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs @@ -2,7 +2,7 @@ namespace OrchardCore.Sms.Azure; -public class AzureSmsPermissionProvider : IPermissionProvider +public sealed class AzureSmsPermissionProvider : IPermissionProvider { public static readonly Permission ManageSmsSettings = AzureSmsPermissions.ManageAzureSmsSettings; @@ -11,7 +11,8 @@ public class AzureSmsPermissionProvider : IPermissionProvider ManageSmsSettings, ]; - public Task> GetPermissionsAsync() => Task.FromResult(_allPermissions); + public Task> GetPermissionsAsync() + => Task.FromResult(_allPermissions); public IEnumerable GetDefaultStereotypes() => [ diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs index 8e661b04b49..5a84e745f00 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs @@ -2,7 +2,7 @@ namespace OrchardCore.Sms.Azure; -public class AzureSmsPermissions +public static class AzureSmsPermissions { public static readonly Permission ManageAzureSmsSettings = new("ManageAzureSmsSettings", "Manage Azure SMS Settings"); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj index 820748ec57e..221a457cbd2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj @@ -7,7 +7,7 @@ $(OCCMSDescription) - The Azure SMS module provides a way to send SMS messages using Azure Communication Services (ACS). + The Azure SMS module enables sending SMS messages via Azure Communication Services (ACS). $(PackageTags) OrchardCoreCMS diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs index a4343350c05..93546b1fedd 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -10,7 +10,7 @@ namespace OrchardCore.Sms.Azure.Services; -public class AzureSmsProvider : ISmsProvider +public sealed class AzureSmsProvider : ISmsProvider { private readonly ISiteService _siteService; private readonly IDataProtectionProvider _dataProtectionProvider; @@ -18,7 +18,7 @@ public class AzureSmsProvider : ISmsProvider private AzureSmsSettings _settings; - protected readonly IStringLocalizer S; + internal readonly IStringLocalizer S; public const string TechnicalName = "Azure"; @@ -69,10 +69,7 @@ public async Task SendAsync(SmsMessage message) { return SmsResult.Success; } - else - { - return SmsResult.Failed(S["SMS message was not send."]); - } + return SmsResult.Failed(S["SMS message was not send."]); } catch (Exception ex) { @@ -86,7 +83,7 @@ private async Task GetSettingsAsync() { if (_settings == null) { - var settings = (await _siteService.GetSiteSettingsAsync()).As(); + var settings = await _siteService.GetSiteSettingsAsync(); var protector = _dataProtectionProvider.CreateProtector(ProtectorName); diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs index ded47cd2ea3..f9f28b46acc 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -8,7 +8,7 @@ namespace OrchardCore.Sms.Azure; -public class Startup : StartupBase +public sealed class Startup : StartupBase { private readonly IHostEnvironment _hostEnvironment; @@ -28,7 +28,7 @@ public override void ConfigureServices(IServiceCollection services) } services.AddTwilioSmsProvider() - .AddScoped, AzureSettingsDisplayDriver>(); + .AddSiteSettingsDisplayDriver(); services.AddScoped(); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs index f31ed32dd1d..d5dad11dd86 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs @@ -10,8 +10,6 @@ public class AzureSettingsViewModel : SmsSettingsBaseViewModel public string ConnectionString { get; set; } public string PhoneNumber { get; set; } - - [BindNever] public bool HasConnectionString { get; set; } } From 38aba4fa8340f4ea7d45c4fc870ce3d0d171dc7a Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 16:36:52 +0300 Subject: [PATCH 08/33] Enhancements --- .../AzureSmsPermissionProvider.cs | 2 +- .../Drivers/AzureSettingsDisplayDriver.cs | 55 ++++++------ .../Extensions/SmsProviderExtensions.cs | 10 +++ .../OrchardCore.Sms.Azure/Manifest.cs | 8 +- .../Models/AzureSmsOptions.cs | 13 +++ .../Models/DefaultAzureSmsOptions.cs | 5 ++ .../Services/AzureSmsOptionsConfiguration.cs | 39 ++++++++ .../Services/AzureSmsProvider.cs | 89 ++----------------- .../Services/AzureSmsProviderBase.cs | 79 ++++++++++++++++ .../AzureSmsProviderOptionsConfigurations.cs | 49 ++++++++++ .../Services/DefaultAzureSmsProvider.cs | 21 +++++ .../OrchardCore.Sms.Azure/Startup.cs | 21 +---- 12 files changed, 261 insertions(+), 130 deletions(-) create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsOptionsConfiguration.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs create mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs index 97924f78df8..a6f10cc4ae9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs @@ -18,7 +18,7 @@ public IEnumerable GetDefaultStereotypes() => [ new PermissionStereotype { - Name = "Administrator", + Name = OrchardCoreConstants.Roles.Administrator, Permissions = _allPermissions, }, ]; diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index 9bfd898d5c9..9a2d016fe17 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -73,62 +73,67 @@ public override async Task UpdateAsync(ISite site, AzureSmsSetti await context.Updater.TryUpdateModelAsync(model, Prefix); + var smsSettings = site.As(); + var hasChanges = settings.IsEnabled != model.IsEnabled; if (!model.IsEnabled) { - var smsSettings = site.As(); - if (hasChanges && smsSettings.DefaultProviderName == AzureSmsProvider.TechnicalName) { smsSettings.DefaultProviderName = null; site.Put(smsSettings); } - - settings.IsEnabled = false; } else { - settings.IsEnabled = true; + hasChanges |= model.PhoneNumber != settings.PhoneNumber; - if (string.IsNullOrWhiteSpace(model.PhoneNumber)) + if (string.IsNullOrEmpty(model.PhoneNumber)) { - context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Invalid Phone number."]); + context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["The phone number is a required."]); } else if (!_phoneFormatValidator.IsValid(model.PhoneNumber)) { context.Updater.ModelState.AddModelError(Prefix, nameof(model.PhoneNumber), S["Invalid phone number."]); } - if (string.IsNullOrWhiteSpace(model.ConnectionString)) - { - context.Updater.ModelState.AddModelError(Prefix, nameof(model.ConnectionString), S["The ConnectionString is required."]); - } - - // Has change should be evaluated before updating the value. - hasChanges |= settings.PhoneNumber != model.PhoneNumber; - hasChanges |= settings.ConnectionString != model.ConnectionString; - settings.PhoneNumber = model.PhoneNumber; - settings.ConnectionString = model.ConnectionString; - if (!string.IsNullOrWhiteSpace(model.ConnectionString)) + if (string.IsNullOrWhiteSpace(model.ConnectionString) && settings.ConnectionString is null) + { + context.Updater.ModelState.AddModelError(Prefix, nameof(model.ConnectionString), S["Connection string is required."]); + } + else if (!string.IsNullOrWhiteSpace(model.ConnectionString)) { - var protector = _dataProtectionProvider.CreateProtector(AzureSmsProvider.ProtectorName); + var protector = _dataProtectionProvider.CreateProtector(AzureSmsOptionsConfiguration.ProtectorName); - var protectedToken = protector.Protect(model.ConnectionString); + var protectedConnection = protector.Protect(model.ConnectionString); - hasChanges |= settings.ConnectionString != protectedToken; + // Check if the connection string changed before setting it. + hasChanges |= protectedConnection != settings.ConnectionString; - settings.ConnectionString = protectedToken; + settings.ConnectionString = protectedConnection; } } - if (hasChanges) + if (context.Updater.ModelState.IsValid) { - _shellReleaseManager.RequestRelease(); + if (settings.IsEnabled && string.IsNullOrEmpty(smsSettings.DefaultProviderName)) + { + // If we are enabling the only provider, set it as the default one. + smsSettings.DefaultProviderName = AzureSmsProvider.TechnicalName; + site.Put(smsSettings); + + hasChanges = true; + } + + if (hasChanges) + { + _shellReleaseManager.RequestRelease(); + } } - return Edit(site, settings, context); + return await EditAsync(site, settings, context); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs new file mode 100644 index 00000000000..628fcb6b672 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs @@ -0,0 +1,10 @@ +using Microsoft.Extensions.DependencyInjection; +using OrchardCore.Sms.Azure.Services; + +namespace OrchardCore.Sms.Azure; + +public static class SmsProviderExtensions +{ + public static IServiceCollection AddAzureSmsProvider(this IServiceCollection services) + => services.AddSmsProviderOptionsConfiguration(); +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs index 8ae08875efd..2b8c843bbe9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs @@ -7,8 +7,12 @@ )] [assembly: Feature( - Name = "Azure SMS", + Name = "Azure SMS Provider", Id = "OrchardCore.Sms.Azure", - Description = "Provides settings and services to send SMS messages using Azure Communication Services (ACS).", + Description = "Enables the ability to send SMS messages through Azure Communication Services (ACS).", + Dependencies = + [ + "OrchardCore.Sms" + ], Category = "SMS" )] diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs new file mode 100644 index 00000000000..444a4312d4a --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs @@ -0,0 +1,13 @@ +namespace OrchardCore.Sms.Azure.Models; + +public class AzureSmsOptions +{ + public bool IsEnabled { get; set; } + + public string PhoneNumber { get; set; } + + public string ConnectionString { get; set; } + + public bool ConfigurationExists() + => !string.IsNullOrWhiteSpace(PhoneNumber) && !string.IsNullOrWhiteSpace(ConnectionString); +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs new file mode 100644 index 00000000000..8ca7b58a30c --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs @@ -0,0 +1,5 @@ +namespace OrchardCore.Sms.Azure.Models; + +public class DefaultAzureSmsOptions : AzureSmsOptions +{ +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsOptionsConfiguration.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsOptionsConfiguration.cs new file mode 100644 index 00000000000..31cb81916e6 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsOptionsConfiguration.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Options; +using OrchardCore.Settings; +using OrchardCore.Sms.Azure.Models; + +namespace OrchardCore.Sms.Azure.Services; + +public sealed class AzureSmsOptionsConfiguration : IConfigureOptions +{ + public const string ProtectorName = "AzureSmsProtector"; + + private readonly ISiteService _siteService; + private readonly IDataProtectionProvider _dataProtectionProvider; + + public AzureSmsOptionsConfiguration( + ISiteService siteService, + IDataProtectionProvider dataProtectionProvider) + { + _siteService = siteService; + _dataProtectionProvider = dataProtectionProvider; + } + + public void Configure(AzureSmsOptions options) + { + var settings = _siteService.GetSettingsAsync() + .GetAwaiter() + .GetResult(); + + options.IsEnabled = settings.IsEnabled; + options.PhoneNumber = settings.PhoneNumber; + + if (!string.IsNullOrEmpty(settings.ConnectionString)) + { + var protector = _dataProtectionProvider.CreateProtector(ProtectorName); + + options.ConnectionString = protector.Unprotect(settings.ConnectionString); + } + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs index 93546b1fedd..d2973117504 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -1,99 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Azure.Communication.Sms; -using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; -using OrchardCore.Settings; +using Microsoft.Extensions.Options; using OrchardCore.Sms.Azure.Models; namespace OrchardCore.Sms.Azure.Services; -public sealed class AzureSmsProvider : ISmsProvider +public sealed class AzureSmsProvider : AzureSmsProviderBase { - private readonly ISiteService _siteService; - private readonly IDataProtectionProvider _dataProtectionProvider; - private readonly ILogger _logger; - - private AzureSmsSettings _settings; - - internal readonly IStringLocalizer S; - public const string TechnicalName = "Azure"; - public const string ProtectorName = "Azure"; - - public LocalizedString Name => S["Azure"]; - public AzureSmsProvider( - ISiteService siteService, - IDataProtectionProvider dataProtectionProvider, + IOptions options, + IPhoneFormatValidator phoneFormatValidator, ILogger logger, IStringLocalizer stringLocalizer) + : base(options.Value, phoneFormatValidator, logger, stringLocalizer) { - _siteService = siteService; - _dataProtectionProvider = dataProtectionProvider; - _logger = logger; - S = stringLocalizer; } - public async Task SendAsync(SmsMessage message) - { - ArgumentNullException.ThrowIfNull(message); - - if (string.IsNullOrEmpty(message.To)) - { - throw new ArgumentException("A phone number is required in order to send a message."); - } - - if (string.IsNullOrEmpty(message.Body)) - { - throw new ArgumentException("A message body is required in order to send a message."); - } - - try - { - var settings = await GetSettingsAsync(); - var data = new List> - { - new ("From", settings.PhoneNumber), - new ("To", message.To), - new ("Body", message.Body), - }; - - var client = new SmsClient(settings.ConnectionString); - var response = await client.SendAsync(settings.PhoneNumber, message.To, message.Body); - - if (response.Value.Successful) - { - return SmsResult.Success; - } - return SmsResult.Failed(S["SMS message was not send."]); - } - catch (Exception ex) - { - _logger.LogError(ex, "Azure service was unable to send SMS messages."); - - return SmsResult.Failed(S["SMS message was not send. Error: {0}", ex.Message]); - } - } - - private async Task GetSettingsAsync() - { - if (_settings == null) - { - var settings = await _siteService.GetSiteSettingsAsync(); - - var protector = _dataProtectionProvider.CreateProtector(ProtectorName); - - _settings = new AzureSmsSettings - { - ConnectionString = settings.ConnectionString == null ? null : protector.Unprotect(settings.ConnectionString), - PhoneNumber = settings.PhoneNumber - }; - } - - return _settings; - } + public override LocalizedString Name => S["Azure Communication Service"]; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs new file mode 100644 index 00000000000..1577a508f0c --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs @@ -0,0 +1,79 @@ +using Azure.Communication.Sms; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using OrchardCore.Sms.Azure.Models; + +namespace OrchardCore.Sms.Azure.Services; + +public abstract class AzureSmsProviderBase : ISmsProvider +{ + private readonly AzureSmsOptions _providerOptions; + private readonly IPhoneFormatValidator _phoneFormatValidator; + private readonly ILogger _logger; + + protected readonly IStringLocalizer S; + + public AzureSmsProviderBase( + AzureSmsOptions options, + IPhoneFormatValidator phoneFormatValidator, + ILogger logger, + IStringLocalizer stringLocalizer) + { + _providerOptions = options; + _phoneFormatValidator = phoneFormatValidator; + _logger = logger; + S = stringLocalizer; + } + + public abstract LocalizedString Name { get; } + + public virtual async Task SendAsync(SmsMessage message) + { + ArgumentNullException.ThrowIfNull(message); + + if (!_providerOptions.IsEnabled) + { + return SmsResult.Failed(S["The Azure SMS Provider is disabled."]); + } + + _logger.LogDebug("Attempting to send SMS to {Recipent}.", message.To); + + if (string.IsNullOrWhiteSpace(message.To)) + { + return SmsResult.Failed(S["The phone number for the recipent is required.", message.To]); + } + else + { + if (!_phoneFormatValidator.IsValid(message.To)) + { + return SmsResult.Failed(S["Invalid phone format for the recipent: '{0}'.", message.To]); + } + + message.To = message.To; + } + + if (string.IsNullOrEmpty(message.Body)) + { + throw new ArgumentException("A message body is required."); + } + + try + { + var client = new SmsClient(_providerOptions.ConnectionString); + var response = await client.SendAsync(_providerOptions.PhoneNumber, message.To, message.Body); + + if (response.Value.Successful) + { + return SmsResult.Success; + } + + return SmsResult.Failed(S["SMS message was not send."]); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while sending an SMS using the Azure SMS Provider."); + + return SmsResult.Failed(S["An error occurred while sending an SMS."]); + } + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs new file mode 100644 index 00000000000..db872f7769a --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Options; +using OrchardCore.Sms.Azure.Models; + +namespace OrchardCore.Sms.Azure.Services; + +public sealed class AzureSmsProviderOptionsConfigurations : IConfigureOptions +{ + private readonly AzureSmsOptions _azureOptions; + private readonly DefaultAzureSmsOptions _defaultAzureOptions; + + public AzureSmsProviderOptionsConfigurations( + IOptions azureOptions, + IOptions defaultAzureOptions) + { + _azureOptions = azureOptions.Value; + _defaultAzureOptions = defaultAzureOptions.Value; + } + + public void Configure(SmsProviderOptions options) + { + ConfigureTenantProvider(options); + + if (_defaultAzureOptions.IsEnabled) + { + // Only configure the default provider, if settings are provided by the configuration provider. + ConfigureDefaultProvider(options); + } + } + + private void ConfigureTenantProvider(SmsProviderOptions options) + { + var typeOptions = new SmsProviderTypeOptions(typeof(AzureSmsProvider)) + { + IsEnabled = _azureOptions.IsEnabled, + }; + + options.TryAddProvider(AzureSmsProvider.TechnicalName, typeOptions); + } + + private static void ConfigureDefaultProvider(SmsProviderOptions options) + { + var typeOptions = new SmsProviderTypeOptions(typeof(DefaultAzureSmsProvider)) + { + IsEnabled = true, + }; + + options.TryAddProvider(DefaultAzureSmsProvider.TechnicalName, typeOptions); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs new file mode 100644 index 00000000000..efd136a9b42 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using OrchardCore.Sms.Azure.Models; + +namespace OrchardCore.Sms.Azure.Services; + +public class DefaultAzureSmsProvider : AzureSmsProviderBase +{ + public const string TechnicalName = "DefaultAzure"; + + public DefaultAzureSmsProvider( + IOptions options, + IPhoneFormatValidator phoneFormatValidator, + ILogger logger, + IStringLocalizer stringLocalizer) : base(options.Value, phoneFormatValidator, logger, stringLocalizer) + { + } + + public override LocalizedString Name => S["Default Azure Communication Service"]; +} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs index f9f28b46acc..216dfbddec2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -1,34 +1,17 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using OrchardCore.DisplayManagement.Handlers; using OrchardCore.Modules; using OrchardCore.Security.Permissions; -using OrchardCore.Settings; using OrchardCore.Sms.Azure.Drivers; namespace OrchardCore.Sms.Azure; public sealed class Startup : StartupBase { - private readonly IHostEnvironment _hostEnvironment; - - public Startup(IHostEnvironment hostEnvironment) - { - _hostEnvironment = hostEnvironment; - } - public override void ConfigureServices(IServiceCollection services) { - services.AddSmsServices(); - services.AddPhoneFormatValidator(); - - if (_hostEnvironment.IsDevelopment()) - { - services.AddLogSmsProvider(); - } - - services.AddTwilioSmsProvider() - .AddSiteSettingsDisplayDriver(); + services.AddAzureSmsProvider() + .AddSiteDisplayDriver(); services.AddScoped(); } From 693951d490983d4bce31d7c0cbadeb4959eeab3e Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 16:47:30 +0300 Subject: [PATCH 09/33] Use SmsResult --- .../OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs index 1577a508f0c..fd399c69df1 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs @@ -54,7 +54,7 @@ public virtual async Task SendAsync(SmsMessage message) if (string.IsNullOrEmpty(message.Body)) { - throw new ArgumentException("A message body is required."); + return SmsResult.Failed(S["The message body is required.", message.To]); } try From 4dd1256401d1e98138fe278946ed0e3b75416e73 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 16:49:01 +0300 Subject: [PATCH 10/33] Fix broken unit test --- .../Services/AzureSmsProviderTests.cs | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs index 1f61d954e66..5827561cee2 100644 --- a/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs @@ -1,6 +1,4 @@ -using OrchardCore.Settings; using OrchardCore.Sms.Azure.Models; -using OrchardCore.Tests.Utilities; namespace OrchardCore.Sms.Azure.Services.Tests; @@ -10,10 +8,15 @@ public class AzureSmsProviderTests public async Task SendSmsShouldSucceed() { // Arrange - var siteSettings = GetSiteService(); + var azureSmsOptions = new AzureSmsOptions + { + IsEnabled = true, + PhoneNumber = "<>", + ConnectionString = "<>" + }; var azureSmsProvider = new AzureSmsProvider( - siteSettings, - Mock.Of(), + Options.Create(azureSmsOptions), + Mock.Of(), Mock.Of>(), Mock.Of>()); var message = new SmsMessage @@ -28,20 +31,4 @@ public async Task SendSmsShouldSucceed() // Assert Assert.True(result.Succeeded); } - - private static ISiteService GetSiteService() - { - var azureSmsSettings = new AzureSmsSettings - { - PhoneNumber = "<>", - ConnectionString = "<>" - }; - var siteServiceMock = new Mock(); - - siteServiceMock. - Setup(siteService => siteService.GetSiteSettingsAsync()). - ReturnsAsync(SiteMockHelper.GetSite(azureSmsSettings).Object); - - return siteServiceMock.Object; - } } From f6559c913cc5ea2e6eb13bf4f7d62c3f6dbc8908 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 20:38:47 +0300 Subject: [PATCH 11/33] Apply suggestions from code review Co-authored-by: Mike Alhayek --- .../OrchardCore.Sms.Azure/AzureSmsPermissions.cs | 2 +- .../Drivers/AzureSettingsDisplayDriver.cs | 3 ++- .../Services/AzureSmsProviderOptionsConfigurations.cs | 2 +- src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs | 2 +- .../OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs | 1 + 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs index 5a84e745f00..e28fe200395 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs @@ -4,5 +4,5 @@ namespace OrchardCore.Sms.Azure; public static class AzureSmsPermissions { - public static readonly Permission ManageAzureSmsSettings = new("ManageAzureSmsSettings", "Manage Azure SMS Settings"); + public static readonly Permission ManageAzureSmsSettings = new("ManageAzureSmsSettings", "Manage Azure Communication SMS Settings"); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index 9a2d016fe17..a8dc9bd4f37 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -28,7 +28,8 @@ public sealed class AzureSettingsDisplayDriver : SiteDisplayDriver SmsSettings.GroupId; + protected override string SettingsGroupId + => SmsSettings.GroupId; public AzureSettingsDisplayDriver( IShellReleaseManager shellReleaseManager, diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs index db872f7769a..dea6ba910a7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs @@ -39,7 +39,7 @@ private void ConfigureTenantProvider(SmsProviderOptions options) private static void ConfigureDefaultProvider(SmsProviderOptions options) { - var typeOptions = new SmsProviderTypeOptions(typeof(DefaultAzureSmsProvider)) + var typeOptions = new SmsProviderTypeOptions(DefaultAzureSmsProvider.TechnicalName) { IsEnabled = true, }; diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs index 216dfbddec2..f6f92b553e4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -13,6 +13,6 @@ public override void ConfigureServices(IServiceCollection services) services.AddAzureSmsProvider() .AddSiteDisplayDriver(); - services.AddScoped(); + services.AddPermissionProvider(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs index d5dad11dd86..8626f12a78a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs @@ -10,6 +10,7 @@ public class AzureSettingsViewModel : SmsSettingsBaseViewModel public string ConnectionString { get; set; } public string PhoneNumber { get; set; } + [BindNever] public bool HasConnectionString { get; set; } } From 50df9f5ce9cd7f58ec83efde79bd0a75e75503ed Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 20:54:13 +0300 Subject: [PATCH 12/33] Fix the build --- .../Services/AzureSmsProviderOptionsConfigurations.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs index dea6ba910a7..58f8993d319 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs @@ -39,7 +39,7 @@ private void ConfigureTenantProvider(SmsProviderOptions options) private static void ConfigureDefaultProvider(SmsProviderOptions options) { - var typeOptions = new SmsProviderTypeOptions(DefaultAzureSmsProvider.TechnicalName) + var typeOptions = new SmsProviderTypeOptions(typeof(AzureSmsProvider)) { IsEnabled = true, }; From b9abd6476729c0282b4ab9e86af2d16fc70ab26d Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 21:04:13 +0300 Subject: [PATCH 13/33] Revert unnecessary changes --- .../.template.config/dotnetcli.host.json | 4 ++-- .../.template.config/template.json | 4 ++-- .../.template.config/dotnetcli.host.json | 2 +- .../.template.config/template.json | 4 ++-- .../.template.config/dotnetcli.host.json | 4 ++-- .../.template.config/template.json | 4 ++-- .../.template.config/dotnetcli.host.json | 4 ++-- .../.template.config/template.json | 4 ++-- .../.template.config/template.json | 4 ++-- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json index 0985e309cd1..e1c98deab31 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/dotnetcli.host.json @@ -12,6 +12,6 @@ }, "usageExamples": [ "--framework net8.0", - "--orchard-version 1.8.3" + "--orchard-version 2.0.0" ] -} \ No newline at end of file +} diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json index 32bcc1b3b65..438ab0b5981 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Module/.template.config/template.json @@ -45,7 +45,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.1.0-preview" + "defaultValue": "2.0.0" } }, "sources": [ @@ -76,4 +76,4 @@ "language": "C#", "type": "project" } -} \ No newline at end of file +} diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json index 154ec41ee08..0139158446a 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/dotnetcli.host.json @@ -17,6 +17,6 @@ "usageExamples": [ "--framework net8.0", "--logger none", - "--orchard-version 1.8.3" + "--orchard-version 2.0.0" ] } diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json index e4304604208..a72f53be27b 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Cms.Web/.template.config/template.json @@ -51,7 +51,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.1.0-preview" + "defaultValue": "2.0.0" }, "UseNLog": { "type": "computed", @@ -78,4 +78,4 @@ "language": "C#", "type": "project" } -} \ No newline at end of file +} diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json index 0985e309cd1..e1c98deab31 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/dotnetcli.host.json @@ -12,6 +12,6 @@ }, "usageExamples": [ "--framework net8.0", - "--orchard-version 1.8.3" + "--orchard-version 2.0.0" ] -} \ No newline at end of file +} diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json index 6e05e3703de..8b078818009 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Module/.template.config/template.json @@ -31,7 +31,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.1.0-preview" + "defaultValue": "2.0.0" } }, "sources": [ @@ -43,4 +43,4 @@ "language": "C#", "type": "project" } -} \ No newline at end of file +} diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json index 0985e309cd1..e1c98deab31 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/dotnetcli.host.json @@ -12,6 +12,6 @@ }, "usageExamples": [ "--framework net8.0", - "--orchard-version 1.8.3" + "--orchard-version 2.0.0" ] -} \ No newline at end of file +} diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json index 053d07ad0f9..1b68b2c47d5 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Mvc.Web/.template.config/template.json @@ -31,7 +31,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.1.0-preview" + "defaultValue": "2.0.0" } }, "sources": [], @@ -39,4 +39,4 @@ "language": "C#", "type": "project" } -} \ No newline at end of file +} diff --git a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json index e9842d31fec..d6ef70ab857 100644 --- a/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json +++ b/src/Templates/OrchardCore.ProjectTemplates/content/OrchardCore.Templates.Theme/.template.config/template.json @@ -37,7 +37,7 @@ "datatype": "string", "description": "Specifies which version of Orchard Core packages to use.", "replaces": "$(TemplateOrchardPackageVersion)", - "defaultValue": "2.1.0-preview" + "defaultValue": "2.0.0" } }, "sources": [ @@ -59,4 +59,4 @@ "language": "C#", "type": "project" } -} \ No newline at end of file +} From 1c9fd3ebf20b8f84d3686d0059a3216c8a72df11 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 22:00:54 +0300 Subject: [PATCH 14/33] Move SmsPermissions to OC.Sms.Core --- .../AzureSmsPermissionProvider.cs | 25 ------------------- .../AzureSmsPermissions.cs | 8 ------ .../Drivers/AzureSettingsDisplayDriver.cs | 4 +-- .../OrchardCore.Sms.Azure/Startup.cs | 3 --- .../OrchardCore.Sms.Core}/SmsPermissions.cs | 0 5 files changed, 2 insertions(+), 38 deletions(-) delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs rename src/{OrchardCore.Modules/OrchardCore.Sms => OrchardCore/OrchardCore.Sms.Core}/SmsPermissions.cs (100%) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs deleted file mode 100644 index a6f10cc4ae9..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissionProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -using OrchardCore.Security.Permissions; - -namespace OrchardCore.Sms.Azure; - -public sealed class AzureSmsPermissionProvider : IPermissionProvider -{ - public static readonly Permission ManageSmsSettings = AzureSmsPermissions.ManageAzureSmsSettings; - - private readonly IEnumerable _allPermissions = - [ - ManageSmsSettings, - ]; - - public Task> GetPermissionsAsync() - => Task.FromResult(_allPermissions); - - public IEnumerable GetDefaultStereotypes() => - [ - new PermissionStereotype - { - Name = OrchardCoreConstants.Roles.Administrator, - Permissions = _allPermissions, - }, - ]; -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs deleted file mode 100644 index e28fe200395..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/AzureSmsPermissions.cs +++ /dev/null @@ -1,8 +0,0 @@ -using OrchardCore.Security.Permissions; - -namespace OrchardCore.Sms.Azure; - -public static class AzureSmsPermissions -{ - public static readonly Permission ManageAzureSmsSettings = new("ManageAzureSmsSettings", "Manage Azure Communication SMS Settings"); -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index a8dc9bd4f37..a30846a584c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -57,7 +57,7 @@ public override IDisplayResult Edit(ISite site, AzureSmsSettings settings, Build model.PhoneNumber = settings.PhoneNumber; model.ConnectionString = settings.ConnectionString; }).Location("Content:5#Azure") - .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, AzureSmsPermissions.ManageAzureSmsSettings)) + .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) .OnGroup(SettingsGroupId); } @@ -65,7 +65,7 @@ public override async Task UpdateAsync(ISite site, AzureSmsSetti { var user = _httpContextAccessor.HttpContext?.User; - if (!await _authorizationService.AuthorizeAsync(user, AzureSmsPermissions.ManageAzureSmsSettings)) + if (!await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) { return null; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs index f6f92b553e4..f6bcc67ad75 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -1,7 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using OrchardCore.DisplayManagement.Handlers; using OrchardCore.Modules; -using OrchardCore.Security.Permissions; using OrchardCore.Sms.Azure.Drivers; namespace OrchardCore.Sms.Azure; @@ -12,7 +11,5 @@ public override void ConfigureServices(IServiceCollection services) { services.AddAzureSmsProvider() .AddSiteDisplayDriver(); - - services.AddPermissionProvider(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms/SmsPermissions.cs b/src/OrchardCore/OrchardCore.Sms.Core/SmsPermissions.cs similarity index 100% rename from src/OrchardCore.Modules/OrchardCore.Sms/SmsPermissions.cs rename to src/OrchardCore/OrchardCore.Sms.Core/SmsPermissions.cs From e208e0c58fc0fd4274d0f167d2e4f96b64e59f3f Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Sep 2024 22:06:41 +0300 Subject: [PATCH 15/33] Address feedback --- .../OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs | 3 ++- .../Services/AzureSmsProviderBase.cs | 10 +++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs index d2973117504..4c19c0b8aa1 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -18,5 +18,6 @@ public AzureSmsProvider( { } - public override LocalizedString Name => S["Azure Communication Service"]; + public override LocalizedString Name + => S["Azure Communication Service"]; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs index fd399c69df1..d297c1e7b00 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs @@ -42,14 +42,10 @@ public virtual async Task SendAsync(SmsMessage message) { return SmsResult.Failed(S["The phone number for the recipent is required.", message.To]); } - else - { - if (!_phoneFormatValidator.IsValid(message.To)) - { - return SmsResult.Failed(S["Invalid phone format for the recipent: '{0}'.", message.To]); - } - message.To = message.To; + if (!_phoneFormatValidator.IsValid(message.To)) + { + return SmsResult.Failed(S["Invalid phone format for the recipent: '{0}'.", message.To]); } if (string.IsNullOrEmpty(message.Body)) From e7d008882cbc8ce47857da8e6c1951cfbc8e5adc Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 13:11:06 -0700 Subject: [PATCH 16/33] Finalize updates --- .../Drivers/AzureSettingsDisplayDriver.cs | 10 ++++------ .../OrchardCore.Sms.Azure/Manifest.cs | 2 +- .../OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs | 3 ++- .../Models/DefaultAzureSmsOptions.cs | 2 +- .../OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs | 2 +- .../Services/AzureSmsProviderBase.cs | 6 +++--- .../Services/AzureSmsProviderOptionsConfigurations.cs | 2 +- .../Services/DefaultAzureSmsProvider.cs | 3 ++- .../ViewModels/AzureSettingsViewModel.cs | 5 +++-- ...ttings.Edit.cshtml => AzureSmsSettings.Edit.cshtml} | 2 +- .../OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj | 4 ++++ .../ViewModels/SmsSettingsBaseViewModel.cs | 6 ------ src/docs/reference/modules/Sms/README.md | 10 ++++++++-- src/docs/releases/2.1.0.md | 6 ++++++ .../OrchardCore.Sms/Services/AzureSmsProviderTests.cs | 2 +- 15 files changed, 38 insertions(+), 27 deletions(-) rename src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/{AzureSettings.Edit.cshtml => AzureSmsSettings.Edit.cshtml} (97%) delete mode 100644 src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index a30846a584c..4943fa2d1ec 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -28,7 +28,7 @@ public sealed class AzureSettingsDisplayDriver : SiteDisplayDriver SmsSettings.GroupId; public AzureSettingsDisplayDriver( @@ -51,21 +51,19 @@ public AzureSettingsDisplayDriver( public override IDisplayResult Edit(ISite site, AzureSmsSettings settings, BuildEditorContext c) { - return Initialize("AzureSettings_Edit", model => + return Initialize("AzureSmsSettings_Edit", model => { model.IsEnabled = settings.IsEnabled; model.PhoneNumber = settings.PhoneNumber; model.ConnectionString = settings.ConnectionString; - }).Location("Content:5#Azure") + }).Location("Content:5#Azure Communication SMS") .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) .OnGroup(SettingsGroupId); } public override async Task UpdateAsync(ISite site, AzureSmsSettings settings, UpdateEditorContext context) { - var user = _httpContextAccessor.HttpContext?.User; - - if (!await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) + if (!await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, SmsPermissions.ManageSmsSettings)) { return null; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs index 2b8c843bbe9..8c79fed9f63 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs @@ -12,7 +12,7 @@ Description = "Enables the ability to send SMS messages through Azure Communication Services (ACS).", Dependencies = [ - "OrchardCore.Sms" + "OrchardCore.Sms", ], Category = "SMS" )] diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs index 444a4312d4a..8a0407dcb42 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/AzureSmsOptions.cs @@ -9,5 +9,6 @@ public class AzureSmsOptions public string ConnectionString { get; set; } public bool ConfigurationExists() - => !string.IsNullOrWhiteSpace(PhoneNumber) && !string.IsNullOrWhiteSpace(ConnectionString); + => !string.IsNullOrWhiteSpace(PhoneNumber) && + !string.IsNullOrWhiteSpace(ConnectionString); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs index 8ca7b58a30c..06ed3434986 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Models/DefaultAzureSmsOptions.cs @@ -1,5 +1,5 @@ namespace OrchardCore.Sms.Azure.Models; -public class DefaultAzureSmsOptions : AzureSmsOptions +public sealed class DefaultAzureSmsOptions : AzureSmsOptions { } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs index 4c19c0b8aa1..39e18fb39e6 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -19,5 +19,5 @@ public AzureSmsProvider( } public override LocalizedString Name - => S["Azure Communication Service"]; + => S["Azure Communication SMS Provider"]; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs index d297c1e7b00..91ab0d2203d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs @@ -36,16 +36,16 @@ public virtual async Task SendAsync(SmsMessage message) return SmsResult.Failed(S["The Azure SMS Provider is disabled."]); } - _logger.LogDebug("Attempting to send SMS to {Recipent}.", message.To); + _logger.LogDebug("Attempting to send SMS to {Recipient}.", message.To); if (string.IsNullOrWhiteSpace(message.To)) { - return SmsResult.Failed(S["The phone number for the recipent is required.", message.To]); + return SmsResult.Failed(S["A phone number is required for the recipient.", message.To]); } if (!_phoneFormatValidator.IsValid(message.To)) { - return SmsResult.Failed(S["Invalid phone format for the recipent: '{0}'.", message.To]); + return SmsResult.Failed(S["Invalid phone number format for the recipient: '{0}'.", message.To]); } if (string.IsNullOrEmpty(message.Body)) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs index 58f8993d319..8893c43fbe3 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs @@ -22,7 +22,7 @@ public void Configure(SmsProviderOptions options) if (_defaultAzureOptions.IsEnabled) { - // Only configure the default provider, if settings are provided by the configuration provider. + // Configure the default provider only if settings are supplied by the configuration provider. ConfigureDefaultProvider(options); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs index efd136a9b42..e446895ea7e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs @@ -17,5 +17,6 @@ public DefaultAzureSmsProvider( { } - public override LocalizedString Name => S["Default Azure Communication Service"]; + public override LocalizedString Name + => S["Default Azure Communication SMS Provider"]; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs index 8626f12a78a..c1194b56309 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs @@ -1,10 +1,11 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; -using OrchardCore.Sms.ViewModels; namespace OrchardCore.Sms.Azure.ViewModels; -public class AzureSettingsViewModel : SmsSettingsBaseViewModel +public class AzureSettingsViewModel { + public string DefaultProvider { get; set; } + public bool IsEnabled { get; set; } public string ConnectionString { get; set; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml similarity index 97% rename from src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml rename to src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml index 1c70a41363f..13d2c44f0ce 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml @@ -7,7 +7,7 @@
- +
diff --git a/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj b/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj index ea178b1502f..a38c30b6308 100644 --- a/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj +++ b/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj @@ -29,4 +29,8 @@ + + + + diff --git a/src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs b/src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs deleted file mode 100644 index f29b6c6d5a3..00000000000 --- a/src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace OrchardCore.Sms.ViewModels; - -public class SmsSettingsBaseViewModel -{ - public string DefaultProvider { get; set; } -} diff --git a/src/docs/reference/modules/Sms/README.md b/src/docs/reference/modules/Sms/README.md index 482f38a81cc..77734c4ea9c 100644 --- a/src/docs/reference/modules/Sms/README.md +++ b/src/docs/reference/modules/Sms/README.md @@ -10,14 +10,20 @@ Enabling the `SMS` feature will add a new settings page under `Configurations` > | --- | --- | | `Log` | This particular provider is exclusively meant for debugging purposes and should never be used in a production environment. It permits the message to be written to the logs. | | `Twilio` | Opting for this provider enables the utilization of Twilio service for sending SMS messages. Edit the SMS settings to enable this provider. | +| `Azure` | Opting for this provider enables the utilization of Azure Communication SMS service for sending SMS messages. This provider will become available after enabling the `Azure SMS Provider` feature. Edit the SMS settings to enable this provider. | !!! note After enabling the SMS feature, you must configure the default provider in order to send SMS messages. -# Configuring Twilio Provider +## Configuring Twilio Provider To enable the [Twilio](https://www.twilio.com) provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Twilio` tab, click the Enable checkbox and provider your Twilio account info. Then in the `Providers` tab, select Twilio as your default provider. +## Azure Communication SMS Provider + +To enable the [Azure Communication SMS](https://learn.microsoft.com/en-us/azure/communication-services/overview) provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Azure Communication SMS` tab, click the Enable checkbox and provider your Azure Communication SMS account info. Then in the `Providers` tab, select 'Azure Communication SMS' as your default provider. + + ## Adding Custom Providers The `OrchardCore.Sms` module provides you with the capability to integrate additional providers for dispatching SMS messages. To achieve this, you can easily create an implementation of the `ISmsProvider` interface and then proceed to register it using one of the following approaches: @@ -77,7 +83,7 @@ public class TestController { var message = new SmsMessage { - To = "17023451234", + To = "+17023451234", Message = "It's easy to send an SMS message using Orchard!", }; diff --git a/src/docs/releases/2.1.0.md b/src/docs/releases/2.1.0.md index 96d4d7e3a43..1a29f249bed 100644 --- a/src/docs/releases/2.1.0.md +++ b/src/docs/releases/2.1.0.md @@ -1,3 +1,9 @@ # Orchard Core 2.1.0 Release date: Not yet released + +## Change Logs + +### New 'Azure Communication SMS Provider' feature + +A new feature was added to allow you to send SMS messages using Azure Communication Services (ACS). Simply enable it then navigate to the admin dashboard > `Configurations` >> `Settings` >> `SMS` to configure the provider. diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs index 5827561cee2..57da6409452 100644 --- a/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs @@ -5,7 +5,7 @@ namespace OrchardCore.Sms.Azure.Services.Tests; public class AzureSmsProviderTests { [Fact(Skip = "Configure the default sender and connection string for SMS Communication Services (ACS) before run this test.")] - public async Task SendSmsShouldSucceed() + public async Task SendAsync_WhenCalled_SuccessfullySendMessage() { // Arrange var azureSmsOptions = new AzureSmsOptions From f482e34873eb0b829ba80443a566d5b011514c73 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 13:52:27 -0700 Subject: [PATCH 17/33] Fix build, improve docs, and fix the default provider --- src/OrchardCore.Cms.Web/appsettings.json | 4 ++++ .../Services/DefaultAzureSmsProvider.cs | 3 ++- .../OrchardCore.Sms.Azure/Startup.cs | 17 +++++++++++++++++ .../ViewModels/AzureSettingsViewModel.cs | 5 ++--- .../OrchardCore.Sms/SmsPermissionProvider.cs | 3 ++- .../OrchardCore.Sms.Core.csproj | 4 ---- .../ViewModels/SmsSettingsBaseViewModel.cs | 6 ++++++ src/docs/reference/modules/Sms/README.md | 17 +++++++++++++++-- 8 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs diff --git a/src/OrchardCore.Cms.Web/appsettings.json b/src/OrchardCore.Cms.Web/appsettings.json index a4e2b9e1074..cc80078f375 100644 --- a/src/OrchardCore.Cms.Web/appsettings.json +++ b/src/OrchardCore.Cms.Web/appsettings.json @@ -254,6 +254,10 @@ // "DefaultSender": "", // "ConnectionString": "" //} + //"OrchardCore_Sms_AzureCommunication": { + // "PhoneNumber": "", + // "ConnectionString": "" + //} //"OrchardCore_ReverseProxy": { // "ForwardedHeaders": "None" //}, diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs index e446895ea7e..599dd0e19ab 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs @@ -13,7 +13,8 @@ public DefaultAzureSmsProvider( IOptions options, IPhoneFormatValidator phoneFormatValidator, ILogger logger, - IStringLocalizer stringLocalizer) : base(options.Value, phoneFormatValidator, logger, stringLocalizer) + IStringLocalizer stringLocalizer) + : base(options.Value, phoneFormatValidator, logger, stringLocalizer) { } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs index f6bcc67ad75..5768a93116c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -1,15 +1,32 @@ +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.Environment.Shell.Configuration; using OrchardCore.Modules; using OrchardCore.Sms.Azure.Drivers; +using OrchardCore.Sms.Azure.Models; namespace OrchardCore.Sms.Azure; public sealed class Startup : StartupBase { + private readonly IShellConfiguration _shellConfiguration; + + public Startup(IShellConfiguration shellConfiguration) + { + _shellConfiguration = shellConfiguration; + } + public override void ConfigureServices(IServiceCollection services) { services.AddAzureSmsProvider() .AddSiteDisplayDriver(); + + services.Configure(options => + { + _shellConfiguration.GetSection("OrchardCore_Sms_AzureCommunication").Bind(options); + + options.IsEnabled = options.ConfigurationExists(); + }); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs index c1194b56309..8626f12a78a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSettingsViewModel.cs @@ -1,11 +1,10 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; +using OrchardCore.Sms.ViewModels; namespace OrchardCore.Sms.Azure.ViewModels; -public class AzureSettingsViewModel +public class AzureSettingsViewModel : SmsSettingsBaseViewModel { - public string DefaultProvider { get; set; } - public bool IsEnabled { get; set; } public string ConnectionString { get; set; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms/SmsPermissionProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms/SmsPermissionProvider.cs index 50207b1cf78..91b277c394b 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms/SmsPermissionProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms/SmsPermissionProvider.cs @@ -4,11 +4,12 @@ namespace OrchardCore.Sms; public sealed class SmsPermissionProvider : IPermissionProvider { + [Obsolete("This should not be used. Instead use SmsPermissions.ManageSmsSettings")] public static readonly Permission ManageSmsSettings = SmsPermissions.ManageSmsSettings; private readonly IEnumerable _allPermissions = [ - ManageSmsSettings, + SmsPermissions.ManageSmsSettings, ]; public Task> GetPermissionsAsync() diff --git a/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj b/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj index a38c30b6308..ea178b1502f 100644 --- a/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj +++ b/src/OrchardCore/OrchardCore.Sms.Core/OrchardCore.Sms.Core.csproj @@ -29,8 +29,4 @@ - - - - diff --git a/src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs b/src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs new file mode 100644 index 00000000000..f29b6c6d5a3 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Sms.Core/ViewModels/SmsSettingsBaseViewModel.cs @@ -0,0 +1,6 @@ +namespace OrchardCore.Sms.ViewModels; + +public class SmsSettingsBaseViewModel +{ + public string DefaultProvider { get; set; } +} diff --git a/src/docs/reference/modules/Sms/README.md b/src/docs/reference/modules/Sms/README.md index 77734c4ea9c..02bed8a20f9 100644 --- a/src/docs/reference/modules/Sms/README.md +++ b/src/docs/reference/modules/Sms/README.md @@ -10,7 +10,6 @@ Enabling the `SMS` feature will add a new settings page under `Configurations` > | --- | --- | | `Log` | This particular provider is exclusively meant for debugging purposes and should never be used in a production environment. It permits the message to be written to the logs. | | `Twilio` | Opting for this provider enables the utilization of Twilio service for sending SMS messages. Edit the SMS settings to enable this provider. | -| `Azure` | Opting for this provider enables the utilization of Azure Communication SMS service for sending SMS messages. This provider will become available after enabling the `Azure SMS Provider` feature. Edit the SMS settings to enable this provider. | !!! note After enabling the SMS feature, you must configure the default provider in order to send SMS messages. @@ -21,8 +20,22 @@ To enable the [Twilio](https://www.twilio.com) provider, navigate to `Configurat ## Azure Communication SMS Provider -To enable the [Azure Communication SMS](https://learn.microsoft.com/en-us/azure/communication-services/overview) provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Azure Communication SMS` tab, click the Enable checkbox and provider your Azure Communication SMS account info. Then in the `Providers` tab, select 'Azure Communication SMS' as your default provider. +To enable the [Azure Communication SMS](https://learn.microsoft.com/en-us/azure/communication-services/overview) providers, you'll need to enable the **Azure Communication SMS** feature. The navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Azure Communication SMS` tab, click the Enable checkbox and provider your Azure Communication SMS account info. Then in the `Providers` tab, select one of the 'Azure Communication SMS' as your default provider. +Enabling this feature will expose the following providers: + +| Provider | Description | +| --- | --- | +| `Azure` | This provider enables tenant-specific Azure Communication Services for sending SMS. Configure the SMS settings to activate this provider. | +| `DefaultAzure` | This provider sets default Azure Communication Service configurations for all tenants.| + +The **DefaultAzure** provider can be configured using any configuration provider. For example, you can use the **appsettings.json** file to set the settings as follows: +```json +"OrchardCore_Sms_AzureCommunication": { + "PhoneNumber": "", + "ConnectionString": "" +} +``` ## Adding Custom Providers From 2205984844f2985a722199f3799655852dca542c Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 14:29:50 -0700 Subject: [PATCH 18/33] Fix the UI --- .../Drivers/AzureSettingsDisplayDriver.cs | 33 +++++++++++-------- .../Extensions/SmsProviderExtensions.cs | 5 ++- .../AzureSmsProviderOptionsConfigurations.cs | 2 +- .../Services/DefaultAzureSmsProvider.cs | 2 +- .../Views/AzureSmsSettings.Edit.cshtml | 22 +++++-------- .../Drivers/SmsSettingsDisplayDriver.cs | 15 ++------- .../Drivers/TwilioSettingsDisplayDriver.cs | 13 ++++++-- 7 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index 4943fa2d1ec..714824dd6b7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Localization; using OrchardCore.DisplayManagement.Entities; using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.Notify; using OrchardCore.DisplayManagement.Views; using OrchardCore.Entities; using OrchardCore.Environment.Shell; @@ -24,6 +25,7 @@ public sealed class AzureSettingsDisplayDriver : SiteDisplayDriver htmlLocalizer, IStringLocalizer stringLocalizer) { @@ -45,6 +48,7 @@ public AzureSettingsDisplayDriver( _authorizationService = authorizationService; _phoneFormatValidator = phoneFormatValidator; _dataProtectionProvider = dataProtectionProvider; + _notifier = notifier; H = htmlLocalizer; S = stringLocalizer; } @@ -55,7 +59,7 @@ public override IDisplayResult Edit(ISite site, AzureSmsSettings settings, Build { model.IsEnabled = settings.IsEnabled; model.PhoneNumber = settings.PhoneNumber; - model.ConnectionString = settings.ConnectionString; + model.HasConnectionString = !string.IsNullOrEmpty(settings.ConnectionString); }).Location("Content:5#Azure Communication SMS") .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) .OnGroup(SettingsGroupId); @@ -79,13 +83,19 @@ public override async Task UpdateAsync(ISite site, AzureSmsSetti { if (hasChanges && smsSettings.DefaultProviderName == AzureSmsProvider.TechnicalName) { + await _notifier.WarningAsync(H["You have successfully disabled the default SMS provider. The SMS service is now disable and will remain disabled until you designate a new default provider."]); + smsSettings.DefaultProviderName = null; site.Put(smsSettings); } + + settings.IsEnabled = false; } else { + settings.IsEnabled = true; + hasChanges |= model.PhoneNumber != settings.PhoneNumber; if (string.IsNullOrEmpty(model.PhoneNumber)) @@ -116,21 +126,18 @@ public override async Task UpdateAsync(ISite site, AzureSmsSetti } } - if (context.Updater.ModelState.IsValid) + if (context.Updater.ModelState.IsValid && settings.IsEnabled && string.IsNullOrEmpty(smsSettings.DefaultProviderName)) { - if (settings.IsEnabled && string.IsNullOrEmpty(smsSettings.DefaultProviderName)) - { - // If we are enabling the only provider, set it as the default one. - smsSettings.DefaultProviderName = AzureSmsProvider.TechnicalName; - site.Put(smsSettings); + // If we are enabling the only provider, set it as the default one. + smsSettings.DefaultProviderName = AzureSmsProvider.TechnicalName; + site.Put(smsSettings); - hasChanges = true; - } + hasChanges = true; + } - if (hasChanges) - { - _shellReleaseManager.RequestRelease(); - } + if (hasChanges) + { + _shellReleaseManager.RequestRelease(); } return await EditAsync(site, settings, context); diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs index 628fcb6b672..8e34e0bb340 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Extensions/SmsProviderExtensions.cs @@ -1,4 +1,6 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using OrchardCore.Sms.Azure.Models; using OrchardCore.Sms.Azure.Services; namespace OrchardCore.Sms.Azure; @@ -6,5 +8,6 @@ namespace OrchardCore.Sms.Azure; public static class SmsProviderExtensions { public static IServiceCollection AddAzureSmsProvider(this IServiceCollection services) - => services.AddSmsProviderOptionsConfiguration(); + => services.AddSmsProviderOptionsConfiguration() + .AddTransient, AzureSmsOptionsConfiguration>(); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs index 8893c43fbe3..59a262017d8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderOptionsConfigurations.cs @@ -39,7 +39,7 @@ private void ConfigureTenantProvider(SmsProviderOptions options) private static void ConfigureDefaultProvider(SmsProviderOptions options) { - var typeOptions = new SmsProviderTypeOptions(typeof(AzureSmsProvider)) + var typeOptions = new SmsProviderTypeOptions(typeof(DefaultAzureSmsProvider)) { IsEnabled = true, }; diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs index 599dd0e19ab..e5993325d63 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs @@ -5,7 +5,7 @@ namespace OrchardCore.Sms.Azure.Services; -public class DefaultAzureSmsProvider : AzureSmsProviderBase +public sealed class DefaultAzureSmsProvider : AzureSmsProviderBase { public const string TechnicalName = "DefaultAzure"; diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml index 13d2c44f0ce..01d9d222262 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml @@ -7,23 +7,13 @@
- +
-
+
-

@T["Azure Account Info"]

- -
- - - - @if (Model.HasConnectionString) - { - @T["Connection String was securely saved. Enter a new value if you wish to replace the existing secret."] - } -
+

@T["Azure Communication Service Info"]

@@ -32,4 +22,10 @@ @T["Phone number must include a country code. For example, +1 for United States."]
+
+ + + +
+
diff --git a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs index aa35378721f..c0f65f8fc88 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/SmsSettingsDisplayDriver.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; @@ -8,7 +7,6 @@ using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Views; using OrchardCore.Environment.Shell; -using OrchardCore.Mvc.ModelBinding; using OrchardCore.Settings; using OrchardCore.Sms.ViewModels; @@ -68,18 +66,11 @@ public override async Task UpdateAsync(ISite site, SmsSettings s await context.Updater.TryUpdateModelAsync(model, Prefix); - if (string.IsNullOrEmpty(model.DefaultProvider)) + if (settings.DefaultProviderName != model.DefaultProvider) { - context.Updater.ModelState.AddModelError(Prefix, nameof(model.DefaultProvider), S["You must select a default provider."]); - } - else - { - if (settings.DefaultProviderName != model.DefaultProvider) - { - settings.DefaultProviderName = model.DefaultProvider; + settings.DefaultProviderName = model.DefaultProvider; - _shellReleaseManager.RequestRelease(); - } + _shellReleaseManager.RequestRelease(); } return Edit(site, settings, context); diff --git a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs index 96e611ebb3e..d6651606d9f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms/Drivers/TwilioSettingsDisplayDriver.cs @@ -79,11 +79,10 @@ public override async Task UpdateAsync(ISite site, TwilioSetting await context.Updater.TryUpdateModelAsync(model, Prefix); var hasChanges = settings.IsEnabled != model.IsEnabled; + var smsSettings = site.As(); if (!model.IsEnabled) { - var smsSettings = site.As(); - if (hasChanges && smsSettings.DefaultProviderName == TwilioSmsProvider.TechnicalName) { await _notifier.WarningAsync(H["You have successfully disabled the default SMS provider. The SMS service is now disable and will remain disabled until you designate a new default provider."]); @@ -136,6 +135,16 @@ public override async Task UpdateAsync(ISite site, TwilioSetting } } + if (context.Updater.ModelState.IsValid && settings.IsEnabled && string.IsNullOrEmpty(smsSettings.DefaultProviderName)) + { + // If we are enabling the only provider, set it as the default one. + smsSettings.DefaultProviderName = TwilioSmsProvider.TechnicalName; + + site.Put(smsSettings); + + hasChanges = true; + } + if (hasChanges) { _shellReleaseManager.RequestRelease(); From fddf6971d75a76128af5fe9b58e61c7774192796 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 15 Sep 2024 07:47:36 +0300 Subject: [PATCH 19/33] Updates --- src/OrchardCore.Cms.Web/appsettings.json | 2 +- .../Drivers/AzureSettingsDisplayDriver.cs | 2 +- .../Services/AzureSmsProvider.cs | 2 +- .../Services/DefaultAzureSmsProvider.cs | 2 +- .../OrchardCore.Sms.Azure/Startup.cs | 2 +- .../ViewModels/AzureSmsTaskViewModel.cs | 8 ----- .../Views/AzureSmsSettings.Edit.cshtml | 6 ++-- .../Services/AzureSmsProviderTests.cs | 34 ------------------- 8 files changed, 7 insertions(+), 51 deletions(-) delete mode 100644 src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSmsTaskViewModel.cs delete mode 100644 test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs diff --git a/src/OrchardCore.Cms.Web/appsettings.json b/src/OrchardCore.Cms.Web/appsettings.json index cc80078f375..774dd51b4ae 100644 --- a/src/OrchardCore.Cms.Web/appsettings.json +++ b/src/OrchardCore.Cms.Web/appsettings.json @@ -254,7 +254,7 @@ // "DefaultSender": "", // "ConnectionString": "" //} - //"OrchardCore_Sms_AzureCommunication": { + //"OrchardCore_Sms_AzureCommunicationServices": { // "PhoneNumber": "", // "ConnectionString": "" //} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index 714824dd6b7..8ab165e8ead 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -60,7 +60,7 @@ public override IDisplayResult Edit(ISite site, AzureSmsSettings settings, Build model.IsEnabled = settings.IsEnabled; model.PhoneNumber = settings.PhoneNumber; model.HasConnectionString = !string.IsNullOrEmpty(settings.ConnectionString); - }).Location("Content:5#Azure Communication SMS") + }).Location("Content:5#Azure Communication Services") .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) .OnGroup(SettingsGroupId); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs index 39e18fb39e6..6c29bfb9d3a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -19,5 +19,5 @@ public AzureSmsProvider( } public override LocalizedString Name - => S["Azure Communication SMS Provider"]; + => S["Azure Communication Services SMS Provider"]; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs index e5993325d63..2feb59260a6 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs @@ -19,5 +19,5 @@ public DefaultAzureSmsProvider( } public override LocalizedString Name - => S["Default Azure Communication SMS Provider"]; + => S["Default Azure Communication Services SMS Provider"]; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs index 5768a93116c..8b899739ac3 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Startup.cs @@ -24,7 +24,7 @@ public override void ConfigureServices(IServiceCollection services) services.Configure(options => { - _shellConfiguration.GetSection("OrchardCore_Sms_AzureCommunication").Bind(options); + _shellConfiguration.GetSection("OrchardCore_Sms_AzureCommunicationServices").Bind(options); options.IsEnabled = options.ConfigurationExists(); }); diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSmsTaskViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSmsTaskViewModel.cs deleted file mode 100644 index 27aa6f09286..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/ViewModels/AzureSmsTaskViewModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace OrchardCore.Sms.Azure.ViewModels; - -public class AzureSmsTaskViewModel -{ - public string PhoneNumber { get; set; } - - public string Body { get; set; } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml index 01d9d222262..bac1ca14759 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml @@ -7,19 +7,17 @@
- +
-

@T["Azure Communication Service Info"]

-
- @T["Phone number must include a country code. For example, +1 for United States."] + @T["The default phone number to use as a sender. Phone number must include a country code. For example, +1 for United States."]
diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs deleted file mode 100644 index 57da6409452..00000000000 --- a/test/OrchardCore.Tests/Modules/OrchardCore.Sms/Services/AzureSmsProviderTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using OrchardCore.Sms.Azure.Models; - -namespace OrchardCore.Sms.Azure.Services.Tests; - -public class AzureSmsProviderTests -{ - [Fact(Skip = "Configure the default sender and connection string for SMS Communication Services (ACS) before run this test.")] - public async Task SendAsync_WhenCalled_SuccessfullySendMessage() - { - // Arrange - var azureSmsOptions = new AzureSmsOptions - { - IsEnabled = true, - PhoneNumber = "<>", - ConnectionString = "<>" - }; - var azureSmsProvider = new AzureSmsProvider( - Options.Create(azureSmsOptions), - Mock.Of(), - Mock.Of>(), - Mock.Of>()); - var message = new SmsMessage - { - To = "test@orchardcore.net", - Body = "This is a test message." - }; - - // Act - var result = await azureSmsProvider.SendAsync(message); - - // Assert - Assert.True(result.Succeeded); - } -} From 2f3d04505cc78b0b084c8dc5415669c9ca75abdd Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 22:05:08 -0700 Subject: [PATCH 20/33] Update AzureSettingsDisplayDriver.cs --- .../OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index 8ab165e8ead..f7512bc1902 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -140,6 +140,6 @@ public override async Task UpdateAsync(ISite site, AzureSmsSetti _shellReleaseManager.RequestRelease(); } - return await EditAsync(site, settings, context); + return Edit(site, settings, context); } } From c88451a78161c8460023b60aec0e6dae6e219032 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 22:05:33 -0700 Subject: [PATCH 21/33] Update README.md --- src/docs/reference/modules/Sms/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/docs/reference/modules/Sms/README.md b/src/docs/reference/modules/Sms/README.md index 02bed8a20f9..acccdc20f45 100644 --- a/src/docs/reference/modules/Sms/README.md +++ b/src/docs/reference/modules/Sms/README.md @@ -30,6 +30,7 @@ Enabling this feature will expose the following providers: | `DefaultAzure` | This provider sets default Azure Communication Service configurations for all tenants.| The **DefaultAzure** provider can be configured using any configuration provider. For example, you can use the **appsettings.json** file to set the settings as follows: + ```json "OrchardCore_Sms_AzureCommunication": { "PhoneNumber": "", From 11270da36fffaf149697bfa1de959d45136235a7 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 22:05:54 -0700 Subject: [PATCH 22/33] Update 2.1.0.md --- src/docs/releases/2.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/releases/2.1.0.md b/src/docs/releases/2.1.0.md index 1a29f249bed..34c90622637 100644 --- a/src/docs/releases/2.1.0.md +++ b/src/docs/releases/2.1.0.md @@ -4,6 +4,6 @@ Release date: Not yet released ## Change Logs -### New 'Azure Communication SMS Provider' feature +### New 'Azure Communication SMS' feature A new feature was added to allow you to send SMS messages using Azure Communication Services (ACS). Simply enable it then navigate to the admin dashboard > `Configurations` >> `Settings` >> `SMS` to configure the provider. From 3b84c608f8e4cf49f9d555613ba3d0bb0a80e7f9 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 22:06:01 -0700 Subject: [PATCH 23/33] Update Manifest.cs --- src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs index 8c79fed9f63..2c2d8819274 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs @@ -7,7 +7,7 @@ )] [assembly: Feature( - Name = "Azure SMS Provider", + Name = "Azure Communication SMS", Id = "OrchardCore.Sms.Azure", Description = "Enables the ability to send SMS messages through Azure Communication Services (ACS).", Dependencies = From 12e06c34cf390145be25aa98ff07339a26ca57eb Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sat, 14 Sep 2024 22:24:08 -0700 Subject: [PATCH 24/33] update --- .../OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs | 7 +++++-- src/docs/reference/modules/Sms/README.md | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs index 91ab0d2203d..1ce57b46099 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs @@ -11,6 +11,8 @@ public abstract class AzureSmsProviderBase : ISmsProvider private readonly IPhoneFormatValidator _phoneFormatValidator; private readonly ILogger _logger; + private SmsClient _smsClient; + protected readonly IStringLocalizer S; public AzureSmsProviderBase( @@ -55,8 +57,9 @@ public virtual async Task SendAsync(SmsMessage message) try { - var client = new SmsClient(_providerOptions.ConnectionString); - var response = await client.SendAsync(_providerOptions.PhoneNumber, message.To, message.Body); + _smsClient ??= new SmsClient(_providerOptions.ConnectionString); + + var response = await _smsClient.SendAsync(_providerOptions.PhoneNumber, message.To, message.Body); if (response.Value.Successful) { diff --git a/src/docs/reference/modules/Sms/README.md b/src/docs/reference/modules/Sms/README.md index acccdc20f45..2363dfdc755 100644 --- a/src/docs/reference/modules/Sms/README.md +++ b/src/docs/reference/modules/Sms/README.md @@ -14,11 +14,11 @@ Enabling the `SMS` feature will add a new settings page under `Configurations` > !!! note After enabling the SMS feature, you must configure the default provider in order to send SMS messages. -## Configuring Twilio Provider +## Configuring the Twilio Providers To enable the [Twilio](https://www.twilio.com) provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Twilio` tab, click the Enable checkbox and provider your Twilio account info. Then in the `Providers` tab, select Twilio as your default provider. -## Azure Communication SMS Provider +## Configuring the Azure Communication SMS Providers To enable the [Azure Communication SMS](https://learn.microsoft.com/en-us/azure/communication-services/overview) providers, you'll need to enable the **Azure Communication SMS** feature. The navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Azure Communication SMS` tab, click the Enable checkbox and provider your Azure Communication SMS account info. Then in the `Providers` tab, select one of the 'Azure Communication SMS' as your default provider. From 93a2dad70120b9c58fa67b9db972e456b02620ab Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 15 Sep 2024 19:32:07 +0300 Subject: [PATCH 25/33] Update docs --- .../OrchardCore.Sms.Azure/Manifest.cs | 2 +- src/docs/reference/README.md | 1 + .../reference/modules/Sms.Azure/README.md | 29 +++++++++++++++++++ src/docs/reference/modules/Sms/README.md | 20 ------------- 4 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 src/docs/reference/modules/Sms.Azure/README.md diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs index 2c2d8819274..e20ac6baac7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs @@ -7,7 +7,7 @@ )] [assembly: Feature( - Name = "Azure Communication SMS", + Name = "Azure SMS", Id = "OrchardCore.Sms.Azure", Description = "Enables the ability to send SMS messages through Azure Communication Services (ACS).", Dependencies = diff --git a/src/docs/reference/README.md b/src/docs/reference/README.md index 47b3823cc12..be5a533107e 100644 --- a/src/docs/reference/README.md +++ b/src/docs/reference/README.md @@ -122,6 +122,7 @@ Here's a categorized overview of all built-in Orchard Core features at a glance. - [Diagnostics](modules/Diagnostics/README.md) - [Remote Deployment](modules/Deployment.Remote/README.md) - [Sms](modules/Sms/README.md) +- [Azure SMS Provider](modules/Sms.Azure/README.md) ### Localization diff --git a/src/docs/reference/modules/Sms.Azure/README.md b/src/docs/reference/modules/Sms.Azure/README.md new file mode 100644 index 00000000000..dc3aa373b41 --- /dev/null +++ b/src/docs/reference/modules/Sms.Azure/README.md @@ -0,0 +1,29 @@ +# Azure SMS (`OrchardCore.Sms.Azure`) + +This module provides an SMS provider for sending SMS through [Azure Communication Services SMS](https://learn.microsoft.com/en-us/azure/communication-services/concepts/sms/concepts). + +## Azure Communication Service Settings + +Enabling this module will introduce a new tab labeled 'Azure' within the SMS settings, allowing you to configure the service. To access these settings, navigate to `Configuration` → `Settings` → `Sms` and click on the 'Azure' tab. The following are the available settings + +| Provider | Description | +| --- | --- | +| `Azure` | This provider enables tenant-specific Azure Communication Services for sending SMS. Configure the SMS settings to activate this provider. | +| `DefaultAzure` | This provider sets default Azure Communication Service configurations for all tenants.| + + +## Default Azure SMS Communication Service Configuration + +You may configure the Default Azure SMS Service provider by the configuration provider using the following settings: + +```json +"OrchardCore_Sms_AzureCommunicationServices": { + "PhoneNumber": "", + "ConnectionString": "" +} +``` + +For more information about configurations, please refer to [Configuration](../../core/Configuration/README.md). + +!!! note + Configuration of the Default Azure SMS provider is not possible through Admin Settings. Utilize the configuration provider for the necessary setup. The provider will appear only if the configuration exists. diff --git a/src/docs/reference/modules/Sms/README.md b/src/docs/reference/modules/Sms/README.md index 2363dfdc755..676304573c0 100644 --- a/src/docs/reference/modules/Sms/README.md +++ b/src/docs/reference/modules/Sms/README.md @@ -18,26 +18,6 @@ Enabling the `SMS` feature will add a new settings page under `Configurations` > To enable the [Twilio](https://www.twilio.com) provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Twilio` tab, click the Enable checkbox and provider your Twilio account info. Then in the `Providers` tab, select Twilio as your default provider. -## Configuring the Azure Communication SMS Providers - -To enable the [Azure Communication SMS](https://learn.microsoft.com/en-us/azure/communication-services/overview) providers, you'll need to enable the **Azure Communication SMS** feature. The navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Azure Communication SMS` tab, click the Enable checkbox and provider your Azure Communication SMS account info. Then in the `Providers` tab, select one of the 'Azure Communication SMS' as your default provider. - -Enabling this feature will expose the following providers: - -| Provider | Description | -| --- | --- | -| `Azure` | This provider enables tenant-specific Azure Communication Services for sending SMS. Configure the SMS settings to activate this provider. | -| `DefaultAzure` | This provider sets default Azure Communication Service configurations for all tenants.| - -The **DefaultAzure** provider can be configured using any configuration provider. For example, you can use the **appsettings.json** file to set the settings as follows: - -```json -"OrchardCore_Sms_AzureCommunication": { - "PhoneNumber": "", - "ConnectionString": "" -} -``` - ## Adding Custom Providers The `OrchardCore.Sms` module provides you with the capability to integrate additional providers for dispatching SMS messages. To achieve this, you can easily create an implementation of the `ISmsProvider` interface and then proceed to register it using one of the following approaches: From 652f93acd88609d22bf01fdcfb3070c9a044c5c0 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 15 Sep 2024 19:39:19 +0300 Subject: [PATCH 26/33] Add SMS provider in navigation --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index c8945c96cd7..4923dd2d663 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -196,6 +196,7 @@ nav: - Shortcodes: reference/modules/Shortcodes/README.md - Sitemaps: reference/modules/Sitemaps/README.md - SMS: reference/modules/Sms/README.md + - Azure SMS Provider: reference/modules/Sms.Azure/README.md - Spatial: reference/modules/Spatial/README.md - XML-RPC: reference/modules/XmlRpc/README.md - Menu: reference/modules/Menu/README.md From 6b59682e7c99f2ca3d514828bb45b31cddd3f390 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 15 Sep 2024 21:53:09 +0300 Subject: [PATCH 27/33] Apply suggestions from code review Co-authored-by: Mike Alhayek --- .../Services/DefaultAzureSmsProvider.cs | 2 +- src/docs/reference/modules/Sms.Azure/README.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs index 2feb59260a6..ef4d59f7fea 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs @@ -19,5 +19,5 @@ public DefaultAzureSmsProvider( } public override LocalizedString Name - => S["Default Azure Communication Services SMS Provider"]; + => S["Default Azure Communication SMS"]; } diff --git a/src/docs/reference/modules/Sms.Azure/README.md b/src/docs/reference/modules/Sms.Azure/README.md index dc3aa373b41..b47abfb6729 100644 --- a/src/docs/reference/modules/Sms.Azure/README.md +++ b/src/docs/reference/modules/Sms.Azure/README.md @@ -1,10 +1,10 @@ # Azure SMS (`OrchardCore.Sms.Azure`) -This module provides an SMS provider for sending SMS through [Azure Communication Services SMS](https://learn.microsoft.com/en-us/azure/communication-services/concepts/sms/concepts). +This feature provides SMS providers for sending SMS through [Azure Communication Services SMS](https://learn.microsoft.com/en-us/azure/communication-services/concepts/sms/concepts). -## Azure Communication Service Settings +## **Azure Communication SMS** Provider Configuration -Enabling this module will introduce a new tab labeled 'Azure' within the SMS settings, allowing you to configure the service. To access these settings, navigate to `Configuration` → `Settings` → `Sms` and click on the 'Azure' tab. The following are the available settings +Enabling this feature will introduce a new tab labeled **Azure** within the SMS settings, allowing you to configure the service. To access these settings from the admin dashboard, navigate to `Configuration` → `Settings` → `Sms` and click on the 'Azure Communication SMS' tab. The following are the available settings. | Provider | Description | | --- | --- | @@ -12,9 +12,9 @@ Enabling this module will introduce a new tab labeled 'Azure' within the SMS set | `DefaultAzure` | This provider sets default Azure Communication Service configurations for all tenants.| -## Default Azure SMS Communication Service Configuration +## **Default Azure Communication SMS** Provider Configuration -You may configure the Default Azure SMS Service provider by the configuration provider using the following settings: +You may configure the **Default Azure Communication SMS** using any configuration provider via the following settings: ```json "OrchardCore_Sms_AzureCommunicationServices": { @@ -26,4 +26,4 @@ You may configure the Default Azure SMS Service provider by the configuration pr For more information about configurations, please refer to [Configuration](../../core/Configuration/README.md). !!! note - Configuration of the Default Azure SMS provider is not possible through Admin Settings. Utilize the configuration provider for the necessary setup. The provider will appear only if the configuration exists. + Configuration of the **Default Azure Communication SMS** provider cannot be performed through Admin Settings. Instead, use the configuration provider for setup. Note that the provider will only appear if the configuration is present. From a63d5f3bffe8322f63af33ca66da02a48dc5307c Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 15 Sep 2024 22:01:22 +0300 Subject: [PATCH 28/33] Refer to docs in release note --- src/docs/releases/2.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/releases/2.1.0.md b/src/docs/releases/2.1.0.md index 34c90622637..fd7b3458ad6 100644 --- a/src/docs/releases/2.1.0.md +++ b/src/docs/releases/2.1.0.md @@ -6,4 +6,4 @@ Release date: Not yet released ### New 'Azure Communication SMS' feature -A new feature was added to allow you to send SMS messages using Azure Communication Services (ACS). Simply enable it then navigate to the admin dashboard > `Configurations` >> `Settings` >> `SMS` to configure the provider. +A new feature was added to allow you to send SMS messages using Azure Communication Services (ACS). Simply enable it then navigate to the admin dashboard > `Configurations` >> `Settings` >> `SMS` to configure the provider. For more information you can refer to the [docs](../reference/modules/Sms.Azure/README.md). From 3b7d00a6b759471427caa8bf47dadb55271fb9e2 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 15 Sep 2024 23:15:05 +0300 Subject: [PATCH 29/33] Apply suggestions from code review Co-authored-by: Mike Alhayek --- mkdocs.yml | 2 +- .../OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs | 2 +- .../OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs | 2 +- .../OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs | 2 +- src/docs/reference/README.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 4923dd2d663..de7f8b0f150 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -196,7 +196,7 @@ nav: - Shortcodes: reference/modules/Shortcodes/README.md - Sitemaps: reference/modules/Sitemaps/README.md - SMS: reference/modules/Sms/README.md - - Azure SMS Provider: reference/modules/Sms.Azure/README.md + - Azure Communication SMS: reference/modules/Sms.Azure/README.md - Spatial: reference/modules/Spatial/README.md - XML-RPC: reference/modules/XmlRpc/README.md - Menu: reference/modules/Menu/README.md diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs index f7512bc1902..cda64d20199 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Drivers/AzureSettingsDisplayDriver.cs @@ -60,7 +60,7 @@ public override IDisplayResult Edit(ISite site, AzureSmsSettings settings, Build model.IsEnabled = settings.IsEnabled; model.PhoneNumber = settings.PhoneNumber; model.HasConnectionString = !string.IsNullOrEmpty(settings.ConnectionString); - }).Location("Content:5#Azure Communication Services") + }).Location("Content:5#Azure Communication") .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings)) .OnGroup(SettingsGroupId); } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs index 6c29bfb9d3a..b892c0664a5 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProvider.cs @@ -19,5 +19,5 @@ public AzureSmsProvider( } public override LocalizedString Name - => S["Azure Communication Services SMS Provider"]; + => S["Azure Communication"]; } diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs index ef4d59f7fea..c408da75f1c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/DefaultAzureSmsProvider.cs @@ -19,5 +19,5 @@ public DefaultAzureSmsProvider( } public override LocalizedString Name - => S["Default Azure Communication SMS"]; + => S["Default Azure Communication"]; } diff --git a/src/docs/reference/README.md b/src/docs/reference/README.md index be5a533107e..38bdd154314 100644 --- a/src/docs/reference/README.md +++ b/src/docs/reference/README.md @@ -122,7 +122,7 @@ Here's a categorized overview of all built-in Orchard Core features at a glance. - [Diagnostics](modules/Diagnostics/README.md) - [Remote Deployment](modules/Deployment.Remote/README.md) - [Sms](modules/Sms/README.md) -- [Azure SMS Provider](modules/Sms.Azure/README.md) +- [Azure Communication SMS](modules/Sms.Azure/README.md) ### Localization From c6523d5374ff1962d55fe411e53690d761741dbf Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 15 Sep 2024 23:51:39 +0300 Subject: [PATCH 30/33] Apply suggestions from code review Co-authored-by: Mike Alhayek --- .../OrchardCore.Sms.Azure/Manifest.cs | 2 +- .../OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj | 2 +- .../Services/AzureSmsProviderBase.cs | 2 +- .../Views/AzureSmsSettings.Edit.cshtml | 2 +- src/docs/reference/modules/Sms.Azure/README.md | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs index e20ac6baac7..2c2d8819274 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Manifest.cs @@ -7,7 +7,7 @@ )] [assembly: Feature( - Name = "Azure SMS", + Name = "Azure Communication SMS", Id = "OrchardCore.Sms.Azure", Description = "Enables the ability to send SMS messages through Azure Communication Services (ACS).", Dependencies = diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj index 221a457cbd2..b6f920f99c4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/OrchardCore.Sms.Azure.csproj @@ -7,7 +7,7 @@ $(OCCMSDescription) - The Azure SMS module enables sending SMS messages via Azure Communication Services (ACS). + The Azure Communication SMS feature enables sending SMS messages via Azure Communication Services (ACS). $(PackageTags) OrchardCoreCMS diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs index 1ce57b46099..e6c43b4d6d7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs @@ -35,7 +35,7 @@ public virtual async Task SendAsync(SmsMessage message) if (!_providerOptions.IsEnabled) { - return SmsResult.Failed(S["The Azure SMS Provider is disabled."]); + return SmsResult.Failed(S["The Azure Communication Provider is disabled."]); } _logger.LogDebug("Attempting to send SMS to {Recipient}.", message.To); diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml index bac1ca14759..39a2938728a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml @@ -7,7 +7,7 @@
- +
diff --git a/src/docs/reference/modules/Sms.Azure/README.md b/src/docs/reference/modules/Sms.Azure/README.md index b47abfb6729..a0178ea9ae1 100644 --- a/src/docs/reference/modules/Sms.Azure/README.md +++ b/src/docs/reference/modules/Sms.Azure/README.md @@ -2,9 +2,9 @@ This feature provides SMS providers for sending SMS through [Azure Communication Services SMS](https://learn.microsoft.com/en-us/azure/communication-services/concepts/sms/concepts). -## **Azure Communication SMS** Provider Configuration +## **Azure Communication** Provider Configuration -Enabling this feature will introduce a new tab labeled **Azure** within the SMS settings, allowing you to configure the service. To access these settings from the admin dashboard, navigate to `Configuration` → `Settings` → `Sms` and click on the 'Azure Communication SMS' tab. The following are the available settings. +Enabling this feature will introduce a new tab labeled **Azure** within the SMS settings, allowing you to configure the service. To access these settings from the admin dashboard, navigate to `Configuration` → `Settings` → `Sms` and click on the 'Azure Communication' tab. The following are the available settings. | Provider | Description | | --- | --- | @@ -12,9 +12,9 @@ Enabling this feature will introduce a new tab labeled **Azure** within the SMS | `DefaultAzure` | This provider sets default Azure Communication Service configurations for all tenants.| -## **Default Azure Communication SMS** Provider Configuration +## **Default Azure Communication** Provider Configuration -You may configure the **Default Azure Communication SMS** using any configuration provider via the following settings: +You may configure the **Default Azure Communication** using any configuration provider via the following settings: ```json "OrchardCore_Sms_AzureCommunicationServices": { @@ -26,4 +26,4 @@ You may configure the **Default Azure Communication SMS** using any configuratio For more information about configurations, please refer to [Configuration](../../core/Configuration/README.md). !!! note - Configuration of the **Default Azure Communication SMS** provider cannot be performed through Admin Settings. Instead, use the configuration provider for setup. Note that the provider will only appear if the configuration is present. + Configuration of the **Default Azure Communication** provider cannot be performed through Admin Settings. Instead, use the configuration provider for setup. Note that the provider will only appear if the configuration is present. From 1826653984655cc6ed22fc2aef38f8bc9ed58eae Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sun, 15 Sep 2024 14:33:30 -0700 Subject: [PATCH 31/33] Update AzureSmsProviderBase.cs --- .../OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs index e6c43b4d6d7..d08119d22e5 100644 --- a/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Sms.Azure/Services/AzureSmsProviderBase.cs @@ -38,7 +38,7 @@ public virtual async Task SendAsync(SmsMessage message) return SmsResult.Failed(S["The Azure Communication Provider is disabled."]); } - _logger.LogDebug("Attempting to send SMS to {Recipient}.", message.To); + _logger.LogDebug("Attempting to send an SMS message using Azure Communication service to {Recipient}.", message.To); if (string.IsNullOrWhiteSpace(message.To)) { From 124231f7a993e8e31dfd2c8a84e28bf9ae240081 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Mon, 16 Sep 2024 00:58:10 +0300 Subject: [PATCH 32/33] Add docs --- src/docs/reference/modules/Sms/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/docs/reference/modules/Sms/README.md b/src/docs/reference/modules/Sms/README.md index 676304573c0..7b43b4ec97f 100644 --- a/src/docs/reference/modules/Sms/README.md +++ b/src/docs/reference/modules/Sms/README.md @@ -18,11 +18,16 @@ Enabling the `SMS` feature will add a new settings page under `Configurations` > To enable the [Twilio](https://www.twilio.com) provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Twilio` tab, click the Enable checkbox and provider your Twilio account info. Then in the `Providers` tab, select Twilio as your default provider. +## Configuring the Azure Communication Providers + +To enable the Azure communication provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Azure Communication` tab, click the Enable checkbox and provider your Twilio account info. Then in the `Providers` tab, select Azure communication as your default provider. For more information refer to [Azure Communication Module](../Sms.Azure/README.md) + ## Adding Custom Providers The `OrchardCore.Sms` module provides you with the capability to integrate additional providers for dispatching SMS messages. To achieve this, you can easily create an implementation of the `ISmsProvider` interface and then proceed to register it using one of the following approaches: If your provider does not require any settings like the `LogProvider`, you may register it like this. + ```csharp services.AddSmsProvider("A technical name for your implementation") ``` From 8b627ca02b07a60b6aee98b5d8e2b671881e22cc Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Sun, 15 Sep 2024 16:56:30 -0700 Subject: [PATCH 33/33] fix docs --- src/docs/reference/modules/Sms/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/docs/reference/modules/Sms/README.md b/src/docs/reference/modules/Sms/README.md index 7b43b4ec97f..dae4526b949 100644 --- a/src/docs/reference/modules/Sms/README.md +++ b/src/docs/reference/modules/Sms/README.md @@ -18,9 +18,9 @@ Enabling the `SMS` feature will add a new settings page under `Configurations` > To enable the [Twilio](https://www.twilio.com) provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Twilio` tab, click the Enable checkbox and provider your Twilio account info. Then in the `Providers` tab, select Twilio as your default provider. -## Configuring the Azure Communication Providers +## Additional Available Providers -To enable the Azure communication provider, navigate to `Configurations` >> `Settings` >> `SMS`. Click on the `Azure Communication` tab, click the Enable checkbox and provider your Twilio account info. Then in the `Providers` tab, select Azure communication as your default provider. For more information refer to [Azure Communication Module](../Sms.Azure/README.md) +- [Azure Communication](../reference/modules/Sms.Azure/README.md) service provider. ## Adding Custom Providers