diff --git a/docs/en/Blob-Storing-Aliyun.md b/docs/en/Blob-Storing-Aliyun.md index 6cdebb3acc..4060e5ba26 100644 --- a/docs/en/Blob-Storing-Aliyun.md +++ b/docs/en/Blob-Storing-Aliyun.md @@ -36,7 +36,7 @@ Configure(options => aliyun.Policy = "policy"; aliyun.DurationSeconds = "expiration date"; aliyun.ContainerName = "your aliyun container name"; - aliyun.CreateContainerIfNotExists = false; + aliyun.CreateContainerIfNotExists = true; }); }); }); diff --git a/docs/en/Blob-Storing-Aws.md b/docs/en/Blob-Storing-Aws.md index 05e3caa183..aa7707e5d3 100644 --- a/docs/en/Blob-Storing-Aws.md +++ b/docs/en/Blob-Storing-Aws.md @@ -39,7 +39,7 @@ Configure(options => Aws.Policy = "policy"; Aws.DurationSeconds = "expiration date"; Aws.ContainerName = "your Aws container name"; - Aws.CreateContainerIfNotExists = false; + Aws.CreateContainerIfNotExists = true; }); }); }); diff --git a/docs/en/Blob-Storing-Azure.md b/docs/en/Blob-Storing-Azure.md index de6ed63152..99833e71c0 100644 --- a/docs/en/Blob-Storing-Azure.md +++ b/docs/en/Blob-Storing-Azure.md @@ -29,7 +29,7 @@ Configure(options => { azure.ConnectionString = "your azure connection string"; azure.ContainerName = "your azure container name"; - azure.CreateContainerIfNotExists = false; + azure.CreateContainerIfNotExists = true; }); }); }); diff --git a/docs/zh-Hans/Blob-Storing-Aliyun.md b/docs/zh-Hans/Blob-Storing-Aliyun.md index c8a1e68bc7..eb67fdbab5 100644 --- a/docs/zh-Hans/Blob-Storing-Aliyun.md +++ b/docs/zh-Hans/Blob-Storing-Aliyun.md @@ -36,7 +36,7 @@ Configure(options => aliyun.Policy = "policy"; aliyun.DurationSeconds = "expiration date"; aliyun.ContainerName = "your aliyun container name"; - aliyun.CreateContainerIfNotExists = false; + aliyun.CreateContainerIfNotExists = true; }); }); }); diff --git a/docs/zh-Hans/Blob-Storing-Aws.md b/docs/zh-Hans/Blob-Storing-Aws.md index 7bfb998297..fc98c5a948 100644 --- a/docs/zh-Hans/Blob-Storing-Aws.md +++ b/docs/zh-Hans/Blob-Storing-Aws.md @@ -39,7 +39,7 @@ Configure(options => Aws.Policy = "policy"; Aws.DurationSeconds = "expiration date"; Aws.ContainerName = "your Aws container name"; - Aws.CreateContainerIfNotExists = false; + Aws.CreateContainerIfNotExists = true; }); }); }); diff --git a/docs/zh-Hans/Blob-Storing-Azure.md b/docs/zh-Hans/Blob-Storing-Azure.md index 8eecc1fde3..e1ed3a6d4e 100644 --- a/docs/zh-Hans/Blob-Storing-Azure.md +++ b/docs/zh-Hans/Blob-Storing-Azure.md @@ -29,7 +29,7 @@ Configure(options => { azure.ConnectionString = "your azure connection string"; azure.ContainerName = "your azure container name"; - azure.CreateContainerIfNotExists = false; + azure.CreateContainerIfNotExists = true; }); }); }); diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 8c2670fa27..d1288de62d 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -361,6 +361,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Tests", "test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Abstractions", "src\Volo.Abp.EventBus.Abstractions\Volo.Abp.EventBus.Abstractions.csproj", "{8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Sms.Aliyun", "src\Volo.Abp.Sms.Aliyun\Volo.Abp.Sms.Aliyun.csproj", "{ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Sms.Aliyun.Tests", "test\Volo.Abp.Sms.Aliyun.Tests\Volo.Abp.Sms.Aliyun.Tests.csproj", "{DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1075,6 +1079,14 @@ Global {8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}.Debug|Any CPU.Build.0 = Debug|Any CPU {8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}.Release|Any CPU.ActiveCfg = Release|Any CPU {8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}.Release|Any CPU.Build.0 = Release|Any CPU + {ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}.Release|Any CPU.Build.0 = Release|Any CPU + {DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1257,6 +1269,8 @@ Global {00D07595-993C-40FC-BD90-0DD6331414D3} = {447C8A77-E5F0-4538-8687-7383196D04EA} {A37BFEB5-7C57-4CDC-93B8-B5CE4BB9ACE1} = {447C8A77-E5F0-4538-8687-7383196D04EA} {8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index 1710fd5bd7..ff7f4913a8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -271,6 +271,7 @@ namespace Volo.Abp.AspNetCore.Mvc actionModel.AddParameter(ParameterApiDescriptionModel.Create( parameterDescription.Name, + _options.ApiParameterNameGenerator?.Invoke(parameterDescription), matchedMethodParamName, parameterDescription.Type, parameterDescription.RouteInfo?.IsOptional ?? false, diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs index 4cd607e07a..f807efcfdf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs @@ -2,6 +2,9 @@ using System.Linq; using System.Reflection; using System.Text; +using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Volo.Abp.Application.Services; using Volo.Abp.AspNetCore.Mvc.Conventions; @@ -13,6 +16,8 @@ namespace Volo.Abp.AspNetCore.Mvc public Func ActionNameGenerator { get; set; } + public Func ApiParameterNameGenerator { get; set; } + public AspNetCoreApiDescriptionModelProviderOptions() { ControllerNameGenerator = (controllerType, setting) => @@ -52,6 +57,28 @@ namespace Volo.Abp.AspNetCore.Mvc return methodNameBuilder.ToString(); }; + + ApiParameterNameGenerator = (apiParameterDescription) => + { + if (apiParameterDescription.ModelMetadata is DefaultModelMetadata defaultModelMetadata) + { + var jsonPropertyNameAttribute = (System.Text.Json.Serialization.JsonPropertyNameAttribute) + defaultModelMetadata?.Attributes?.PropertyAttributes?.FirstOrDefault(x => x is System.Text.Json.Serialization.JsonPropertyNameAttribute); + if (jsonPropertyNameAttribute != null) + { + return jsonPropertyNameAttribute.Name; + } + + var jsonPropertyAttribute = (Newtonsoft.Json.JsonPropertyAttribute) + defaultModelMetadata?.Attributes?.PropertyAttributes?.FirstOrDefault(x => x is Newtonsoft.Json.JsonPropertyAttribute); + if (jsonPropertyAttribute != null) + { + return jsonPropertyAttribute.PropertyName; + } + } + + return null; + }; } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs index 95a961b814..0512e28f7a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs @@ -50,7 +50,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow return; } - //Begin a new, independent unit of work using (var uow = unitOfWorkManager.Begin(options)) { var result = await next(); @@ -58,6 +57,10 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow { await uow.CompleteAsync(context.HttpContext.RequestAborted); } + else + { + await uow.RollbackAsync(context.HttpContext.RequestAborted); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs index 30c713940f..d808053592 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs @@ -55,7 +55,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow return; } - //Begin a new, independent unit of work using (var uow = unitOfWorkManager.Begin(options)) { var result = await next(); @@ -63,6 +62,10 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow { await uow.CompleteAsync(context.HttpContext.RequestAborted); } + else + { + await uow.RollbackAsync(context.HttpContext.RequestAborted); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index c82c434916..de28b8cabf 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -147,19 +147,34 @@ namespace Volo.Abp.Cli.Commands } var createSolutionFolder = GetCreateSolutionFolderPreference(commandLineArgs); - if (!createSolutionFolder) - { - Logger.LogInformation("Create Solution Folder: no"); - } var outputFolder = commandLineArgs.Options.GetOrNull(Options.OutputFolder.Short, Options.OutputFolder.Long); var outputFolderRoot = outputFolder != null ? Path.GetFullPath(outputFolder) : Directory.GetCurrentDirectory(); - outputFolder = createSolutionFolder ? - Path.Combine(outputFolderRoot, SolutionName.Parse(projectName).FullName) : - outputFolderRoot; + SolutionName solutionName; + if (MicroserviceServiceTemplateBase.IsMicroserviceServiceTemplate(template)) + { + var microserviceSolutionName = FindMicroserviceSolutionName(outputFolderRoot); + + if (microserviceSolutionName == null) + { + throw new CliUsageException("This command should be run inside a folder that contains a microservice solution!"); + } + + solutionName = SolutionName.Parse(microserviceSolutionName, projectName); + outputFolder = MicroserviceServiceTemplateBase.CalculateTargetFolder(outputFolderRoot, projectName); + uiFramework = uiFramework == UiFramework.NotSpecified ? FindMicroserviceSolutionUiFramework(outputFolderRoot) : uiFramework; + } + else + { + solutionName = SolutionName.Parse(projectName); + + outputFolder = createSolutionFolder ? + Path.Combine(outputFolderRoot, SolutionName.Parse(projectName).FullName) : + outputFolderRoot; + } Volo.Abp.IO.DirectoryHelper.CreateIfNotExists(outputFolder); @@ -176,7 +191,7 @@ namespace Volo.Abp.Cli.Commands var result = await TemplateProjectBuilder.BuildAsync( new ProjectBuildArgs( - SolutionName.Parse(projectName), + solutionName, template, version, databaseProvider, @@ -245,6 +260,32 @@ namespace Volo.Abp.Cli.Commands } } + private string FindMicroserviceSolutionName(string outputFolderRoot) + { + var slnFile = Directory.GetFiles(outputFolderRoot, "*.sln").FirstOrDefault(); + + if (slnFile == null) + { + return null; + } + + return Path.GetFileName(slnFile).RemovePostFix(".sln"); + } + + private UiFramework FindMicroserviceSolutionUiFramework(string outputFolderRoot) + { + if (Directory.Exists(Path.Combine(outputFolderRoot, "applications", "blazor"))) + { + return UiFramework.Blazor; + } + if (Directory.Exists(Path.Combine(outputFolderRoot, "applications", "web"))) + { + return UiFramework.Mvc; + } + + return UiFramework.None; + } + private void OpenThanksPage(UiFramework uiFramework, DatabaseProvider databaseProvider, bool tiered, bool commercial) { uiFramework = uiFramework == UiFramework.NotSpecified || uiFramework == UiFramework.None ? UiFramework.Mvc : uiFramework; @@ -383,6 +424,11 @@ namespace Volo.Abp.Cli.Commands protected virtual UiFramework GetUiFramework(CommandLineArgs commandLineArgs) { + if (commandLineArgs.Options.ContainsKey("no-ui")) + { + return UiFramework.None; + } + var optionValue = commandLineArgs.Options.GetOrNull(Options.UiFramework.Short, Options.UiFramework.Long); switch (optionValue) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs index 698c7f1d8d..dafdc28dc4 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Xml; using Volo.Abp.Cli.ProjectBuilding.Files; +using Volo.Abp.Cli.ProjectBuilding.Templates.Microservice; using Volo.Abp.Cli.Utils; namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps @@ -25,7 +26,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps var localVoloRepoPath = context.BuildArgs.VoloGitHubLocalRepositoryPath; new ProjectReferenceReplacer.LocalProjectPathReferenceReplacer( - context.Files, + context, context.Module?.Namespace ?? "MyCompanyName.MyProjectName", localAbpRepoPath, localVoloRepoPath @@ -41,7 +42,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps } new ProjectReferenceReplacer.NugetReferenceReplacer( - context.Files, + context, context.Module?.Namespace ?? "MyCompanyName.MyProjectName", nugetPackageVersion ).Run(); @@ -70,13 +71,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps private abstract class ProjectReferenceReplacer { private readonly List _entries; + private readonly bool _isMicroserviceServiceTemplate; private readonly string _projectName; protected ProjectReferenceReplacer( - List entries, + ProjectBuildContext context, string projectName) { - _entries = entries; + _entries = context.Files; + _isMicroserviceServiceTemplate = MicroserviceServiceTemplateBase.IsMicroserviceServiceTemplate(context.Template?.Name); _projectName = projectName; } @@ -113,14 +116,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps var oldNodeIncludeValue = oldNode.Attributes["Include"].Value; // ReSharper disable once PossibleNullReferenceException : Can not be null because nodes are selected with include attribute filter in previous method - if (oldNodeIncludeValue.Contains(_projectName) && _entries.Any(e=>e.Name.EndsWith(GetProjectNameWithExtensionFromProjectReference(oldNodeIncludeValue)))) + if (oldNodeIncludeValue.Contains(_projectName)) { - continue; + if (_isMicroserviceServiceTemplate || _entries.Any(e=>e.Name.EndsWith(GetProjectNameWithExtensionFromProjectReference(oldNodeIncludeValue)))) + { + continue; + } } - XmlNode newNode = null; - - newNode = GetNewReferenceNode(doc, oldNodeIncludeValue); + XmlNode newNode = GetNewReferenceNode(doc, oldNodeIncludeValue); oldNode.ParentNode.ReplaceChild(newNode, oldNode); } @@ -145,8 +149,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { private readonly string _nugetPackageVersion; - public NugetReferenceReplacer(List entries, string projectName, string nugetPackageVersion) - : base(entries, projectName) + public NugetReferenceReplacer(ProjectBuildContext context, string projectName, string nugetPackageVersion) + : base(context, projectName) { _nugetPackageVersion = nugetPackageVersion; } @@ -183,8 +187,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps private readonly string _gitHubAbpLocalRepositoryPath; private readonly string _gitHubVoloLocalRepositoryPath; - public LocalProjectPathReferenceReplacer(List entries, string projectName, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath) - : base(entries, projectName) + public LocalProjectPathReferenceReplacer(ProjectBuildContext context, string projectName, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath) + : base(context, projectName) { _gitHubAbpLocalRepositoryPath = gitHubAbpLocalRepositoryPath; _gitHubVoloLocalRepositoryPath = gitHubVoloLocalRepositoryPath; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromSolutionStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromSolutionStep.cs index 942dd91067..b8c1f24b46 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromSolutionStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromSolutionStep.cs @@ -85,11 +85,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps private void SetSolutionAndProjectPathsIfNull(ProjectBuildContext context) { - if (_solutionFilePath == null) { _solutionFilePath = context.FindFile("/aspnet-core/MyCompanyName.MyProjectName.sln")?.Name ?? - context.FindFile("/MyCompanyName.MyProjectName.sln")?.Name; + context.FindFile("/MyCompanyName.MyProjectName.sln")?.Name ?? + context.FindFile("/MyCompanyName.MyProjectName.MicroserviceName.sln")?.Name; } if (_projectFolderPath == null) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs index ce2c8c3b2a..27199f6ce4 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Volo.Abp.Cli.ProjectBuilding.Files; +using Volo.Abp.Cli.ProjectBuilding.Templates.Microservice; namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { @@ -8,13 +9,26 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { public override void Execute(ProjectBuildContext context) { - new SolutionRenamer( - context.Files, - "MyCompanyName", - "MyProjectName", - context.BuildArgs.SolutionName.CompanyName, - context.BuildArgs.SolutionName.ProjectName - ).Run(); + if (MicroserviceServiceTemplateBase.IsMicroserviceServiceTemplate(context.BuildArgs.TemplateName)) + { + new SolutionRenamer( + context.Files, + "MyCompanyName.MyProjectName", + "MicroserviceName", + context.BuildArgs.SolutionName.CompanyName, + context.BuildArgs.SolutionName.ProjectName + ).Run(); + } + else + { + new SolutionRenamer( + context.Files, + "MyCompanyName", + "MyProjectName", + context.BuildArgs.SolutionName.CompanyName, + context.BuildArgs.SolutionName.ProjectName + ).Run(); + } } private class SolutionRenamer diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs index 8b7cfeb440..3e77f0844e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs @@ -33,7 +33,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building } if ((context.BuildArgs.UiFramework == UiFramework.Mvc || context.BuildArgs.UiFramework == UiFramework.Blazor) - && context.BuildArgs.MobileApp == MobileApp.None && context.Template.Name != MicroserviceProTemplate.TemplateName) + && context.BuildArgs.MobileApp == MobileApp.None && context.Template.Name != MicroserviceProTemplate.TemplateName + && context.Template.Name != MicroserviceServiceProTemplate.TemplateName) { pipeline.Steps.Add(new RemoveRootFolderStep()); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SolutionName.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SolutionName.cs index ba93774fbe..ba55f7aa4c 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SolutionName.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SolutionName.cs @@ -17,6 +17,11 @@ namespace Volo.Abp.Cli.ProjectBuilding ProjectName = projectName; } + public static SolutionName Parse(string fullName, string microserviceName) + { + return new SolutionName(fullName + "." + microserviceName, fullName, microserviceName); + } + public static SolutionName Parse(string fullName) { if (fullName.Length < 1) @@ -47,4 +52,4 @@ namespace Volo.Abp.Cli.ProjectBuilding return new SolutionName(fullName, companyName, projectName); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateInfoProvider.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateInfoProvider.cs index 1a4bf3c05a..05e12e7922 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateInfoProvider.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateInfoProvider.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.Cli.ProjectBuilding public TemplateInfoProvider(ICancellationTokenProvider cancellationTokenProvider, IRemoteServiceExceptionHandler remoteServiceExceptionHandler, - AuthService authService, + AuthService authService, CliHttpClientFactory cliHttpClientFactory) { CancellationTokenProvider = cancellationTokenProvider; @@ -56,6 +56,8 @@ namespace Volo.Abp.Cli.ProjectBuilding return new AppProTemplate(); case MicroserviceProTemplate.TemplateName: return new MicroserviceProTemplate(); + case MicroserviceServiceProTemplate.TemplateName: + return new MicroserviceServiceProTemplate(); case ModuleTemplate.TemplateName: return new ModuleTemplate(); case ModuleProTemplate.TemplateName: diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceProTemplate.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceProTemplate.cs new file mode 100644 index 0000000000..7b7b104033 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceProTemplate.cs @@ -0,0 +1,16 @@ +namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice +{ + public class MicroserviceServiceProTemplate : MicroserviceServiceTemplateBase + { + /// + /// "microservice-service-pro". + /// + public const string TemplateName = "microservice-service-pro"; + + public MicroserviceServiceProTemplate() + : base(TemplateName) + { + DocumentUrl = null; // todo: set this + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs new file mode 100644 index 0000000000..de589336b0 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.IO; +using JetBrains.Annotations; +using Volo.Abp.Cli.ProjectBuilding.Building; +using Volo.Abp.Cli.ProjectBuilding.Building.Steps; + +namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice +{ + public abstract class MicroserviceServiceTemplateBase : TemplateInfo + { + protected MicroserviceServiceTemplateBase([NotNull] string name) + : base(name) + { + } + + public static bool IsMicroserviceServiceTemplate(string templateName) + { + return templateName == MicroserviceServiceProTemplate.TemplateName; + } + + public static string CalculateTargetFolder(string mainSolutionFolder, string serviceName) + { + serviceName = serviceName.ToCamelCase().RemovePostFix("Service"); + + return Path.Combine(mainSolutionFolder, "microservices", serviceName); + } + + public override IEnumerable GetCustomSteps(ProjectBuildContext context) + { + var steps = new List(); + + DeleteUnrelatedUiProject(context, steps); + RandomizeStringEncryption(context, steps); + + return steps; + } + + private static void DeleteUnrelatedUiProject(ProjectBuildContext context, List steps) + { + switch (context.BuildArgs.UiFramework) + { + case UiFramework.Blazor: + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.MicroserviceName.Web")); + break; + case UiFramework.Mvc: + case UiFramework.NotSpecified: + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.MicroserviceName.Blazor")); + break; + default: + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.MicroserviceName.Blazor")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.MicroserviceName.Web")); + break; + } + } + + private static void RandomizeStringEncryption(ProjectBuildContext context, List steps) + { + steps.Add(new RandomizeStringEncryptionStep()); + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs index 52ff3c9c91..0a56f5272a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs @@ -33,27 +33,41 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice switch (context.BuildArgs.UiFramework) { case UiFramework.None: - steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web")); - steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null, + "/applications/web/src/MyCompanyName.MyProjectName.Web")); + steps.Add(new RemoveFolderStep("/applications/web")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, + "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); + steps.Add(new RemoveFolderStep("/applications/blazor")); steps.Add(new RemoveFolderStep("/angular")); break; case UiFramework.Angular: - steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web")); - steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null, + "/applications/web/src/MyCompanyName.MyProjectName.Web")); + steps.Add(new RemoveFolderStep("/applications/web")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, + "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); + steps.Add(new RemoveFolderStep("/applications/blazor")); break; case UiFramework.Blazor: - steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null, + "/applications/web/src/MyCompanyName.MyProjectName.Web")); + steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveFolderStep("/angular")); break; case UiFramework.Mvc: case UiFramework.NotSpecified: - steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, + "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); + steps.Add(new RemoveFolderStep("/applications/blazor")); steps.Add(new RemoveFolderStep("/angular")); break; } + + steps.Add(new RemoveFolderStep("/microservices/template")); } private static void RandomizeStringEncryption(ProjectBuildContext context, List steps) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs index e4e5f0bb2e..08912f2f25 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs @@ -34,7 +34,8 @@ namespace Volo.Abp.Cli.ProjectModification } await AddPathsToTsConfigAsync(angularPath, angularProjectsPath, projects); - + await CreateTsConfigProdJsonAsync(angularPath); + await AddScriptsToPackageJsonAsync(angularPath); await AddProjectToAngularJsonAsync(angularPath, projects); } catch (Exception e) @@ -93,6 +94,61 @@ namespace Volo.Abp.Cli.ProjectModification File.WriteAllText(angularJsonFilePath, json.ToString(Formatting.Indented)); } + private async Task AddScriptsToPackageJsonAsync(string angularPath) + { + var packageJsonFilePath = Path.Combine(angularPath, "package.json"); + var fileContent = File.ReadAllText(packageJsonFilePath); + + var json = JObject.Parse(fileContent); + + var scriptsJobject = (JObject) json["scripts"]; + + if (scriptsJobject == null || scriptsJobject["postinstall"] != null || scriptsJobject["compile:ivy"] != null) + { + return; + } + + scriptsJobject["postinstall"] = "npm run compile:ivy"; + scriptsJobject["compile:ivy"] = "yarn ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points --tsconfig './tsconfig.prod.json' --source node_modules"; + + File.WriteAllText(packageJsonFilePath, json.ToString(Formatting.Indented)); + } + + private async Task CreateTsConfigProdJsonAsync(string angularPath) + { + var tsConfigProdJsonFilePath = Path.Combine(angularPath, "tsconfig.prod.json"); + + if (File.Exists(tsConfigProdJsonFilePath)) + { + return; + } + + var json = new JObject( + new JProperty("compileOnSave", false), + new JProperty("compilerOptions", new JObject( + new JProperty("baseUrl", "./"), + new JProperty("outDir", "./dist/out-tsc"), + new JProperty("sourceMap", true), + new JProperty("declaration", false), + new JProperty("downlevelIteration", true), + new JProperty("experimentalDecorators", true), + new JProperty("module", "esnext"), + new JProperty("moduleResolution", "node"), + new JProperty("importHelpers", true), + new JProperty("target", "es2015"), + new JProperty("typeRoots", new JArray(new JValue("node_modules/@types"))), + new JProperty("lib", new JArray(new JValue("es2018"), new JValue("dom"))), + new JProperty("types", new JArray(new JValue("jest"))) + )), + new JProperty("angularCompilerOptions", new JObject( + new JProperty("fullTemplateTypeCheck", true), + new JProperty("strictInjectionParameters", true) + )) + ); + + File.WriteAllText(tsConfigProdJsonFilePath, json.ToString(Formatting.Indented)); + } + private async Task AddPathsToTsConfigAsync(string angularPath, string angularProjectsPath, List projects) { @@ -105,7 +161,8 @@ namespace Volo.Abp.Cli.ProjectModification { var projectPackageName = await GetProjectPackageNameAsync(angularProjectsPath, project); - var publicApis = Directory.GetFiles(Path.Combine(angularProjectsPath, project), "*public-api.ts", SearchOption.AllDirectories) + var publicApis = Directory.GetFiles(Path.Combine(angularProjectsPath, project), "*public-api.ts", + SearchOption.AllDirectories) .Where(p => !p.Contains("\\node_modules\\")) .Select(p => p.RemovePreFix(angularPath).Replace("\\", "/").RemovePreFix("/")); @@ -171,8 +228,10 @@ namespace Volo.Abp.Cli.ProjectModification { continue; } + Directory.Move(folderUnderProject, Path.Combine(folder, Path.GetFileName(folderUnderProject))); } + projectsInFolder = Directory.GetDirectories(folder); } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs index 8bdead565e..8a12b5847a 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs @@ -10,6 +10,8 @@ namespace Volo.Abp.Http.Modeling public string Name { get; set; } + public string JsonName { get; set; } + public string Type { get; set; } public string TypeSimple { get; set; } @@ -29,11 +31,12 @@ namespace Volo.Abp.Http.Modeling } - public static ParameterApiDescriptionModel Create(string name, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null, string descriptorName = null) + public static ParameterApiDescriptionModel Create(string name, string jsonName, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null, string descriptorName = null) { return new ParameterApiDescriptionModel { Name = name, + JsonName = jsonName, NameOnMethod = nameOnMethod, Type = type != null ? TypeHelper.GetFullNameHandlingNullableAndGenerics(type) : null, TypeSimple = type != null ? ApiTypeNameHelper.GetSimpleTypeName(type) : null, diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs index 786ea32b76..678798ae39 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.Reflection; +using Volo.Abp.Http.ProxyScripting.Configuration; namespace Volo.Abp.Http.Modeling { @@ -9,6 +10,8 @@ namespace Volo.Abp.Http.Modeling { public string Name { get; set; } + public string JsonName { get; set; } + public string Type { get; set; } public string TypeSimple { get; set; } @@ -21,6 +24,7 @@ namespace Volo.Abp.Http.Modeling return new PropertyApiDescriptionModel { Name = propertyInfo.Name, + JsonName = AbpApiProxyScriptingOptions.PropertyNameGenerator.Invoke(propertyInfo), Type = ApiTypeNameHelper.GetTypeName(propertyInfo.PropertyType), TypeSimple = ApiTypeNameHelper.GetSimpleTypeName(propertyInfo.PropertyType), IsRequired = propertyInfo.IsDefined(typeof(RequiredAttribute), true) diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs index e698d00416..21bc6783bb 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; namespace Volo.Abp.Http.ProxyScripting.Configuration { @@ -7,9 +8,30 @@ namespace Volo.Abp.Http.ProxyScripting.Configuration { public IDictionary Generators { get; } + public static Func PropertyNameGenerator { get; set; } + public AbpApiProxyScriptingOptions() { Generators = new Dictionary(); + + PropertyNameGenerator = propertyInfo => + { + var jsonPropertyNameAttribute = propertyInfo.GetSingleAttributeOrNull(true); + + if (jsonPropertyNameAttribute != null) + { + return jsonPropertyNameAttribute.Name; + } + + var jsonPropertyAttribute = propertyInfo.GetSingleAttributeOrNull(true); + + if (jsonPropertyAttribute != null) + { + return jsonPropertyAttribute.PropertyName; + } + + return null; + }; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Sms.Aliyun/FodyWeavers.xml b/framework/src/Volo.Abp.Sms.Aliyun/FodyWeavers.xml new file mode 100644 index 0000000000..0e5296674a --- /dev/null +++ b/framework/src/Volo.Abp.Sms.Aliyun/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Sms.Aliyun/FodyWeavers.xsd b/framework/src/Volo.Abp.Sms.Aliyun/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.Sms.Aliyun/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj b/framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj new file mode 100644 index 0000000000..cae6301daf --- /dev/null +++ b/framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj @@ -0,0 +1,24 @@ + + + + + + netstandard2.0 + Volo.Abp.Sms.Aliyun + Volo.Abp.Sms.Aliyun + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AbpAliyunSmsOptions.cs b/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AbpAliyunSmsOptions.cs new file mode 100644 index 0000000000..4560e5249e --- /dev/null +++ b/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AbpAliyunSmsOptions.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.Sms.Aliyun +{ + public class AbpAliyunSmsOptions + { + public string AccessKeySecret { get; set; } + + public string AccessKeyId { get; set; } + + public string EndPoint { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AbpSmsAliyunModule.cs b/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AbpSmsAliyunModule.cs new file mode 100644 index 0000000000..c1ad646981 --- /dev/null +++ b/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AbpSmsAliyunModule.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Sms.Aliyun +{ + [DependsOn(typeof(AbpSmsModule))] + public class AbpSmsAliyunModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure(configuration.GetSection("AbpAliyunSms")); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AliyunSmsSender.cs b/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AliyunSmsSender.cs new file mode 100644 index 0000000000..bb4d6282cb --- /dev/null +++ b/framework/src/Volo.Abp.Sms.Aliyun/Volo/Abp/Sms/Aliyun/AliyunSmsSender.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using AliyunClient = AlibabaCloud.SDK.Dysmsapi20170525.Client; +using AliyunConfig = AlibabaCloud.OpenApiClient.Models.Config; +using AliyunSendSmsRequest = AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest; + +namespace Volo.Abp.Sms.Aliyun +{ + public class AliyunSmsSender : ISmsSender, ITransientDependency + { + protected AbpAliyunSmsOptions Options { get; } + + public AliyunSmsSender(IOptionsSnapshot options) + { + Options = options.Value; + } + + public async Task SendAsync(SmsMessage smsMessage) + { + var client = CreateClient(); + + await client.SendSmsAsync(new AliyunSendSmsRequest + { + PhoneNumbers = smsMessage.PhoneNumber, + SignName = smsMessage.Properties.GetOrDefault("SignName") as string, + TemplateCode = smsMessage.Properties.GetOrDefault("TemplateCode") as string, + TemplateParam = smsMessage.Text + }); + } + + protected virtual AliyunClient CreateClient() + { + return new(new AliyunConfig + { + AccessKeyId = Options.AccessKeyId, + AccessKeySecret = Options.AccessKeySecret, + Endpoint = Options.EndPoint + }); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo.Abp.Sms.Aliyun.Tests.csproj b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo.Abp.Sms.Aliyun.Tests.csproj new file mode 100644 index 0000000000..d98dd7329a --- /dev/null +++ b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo.Abp.Sms.Aliyun.Tests.csproj @@ -0,0 +1,26 @@ + + + + + + net5.0 + + 9f0d2c00-80c1-435b-bfab-2c39c8249091 + + + + + + + + + + + + + + Always + + + + diff --git a/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AbpSmsAliyunTestBase.cs b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AbpSmsAliyunTestBase.cs new file mode 100644 index 0000000000..976dcda0fd --- /dev/null +++ b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AbpSmsAliyunTestBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Testing; + +namespace Volo.Abp.Sms.Aliyun +{ + public class AbpSmsAliyunTestBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AbpSmsAliyunTestsModule.cs b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AbpSmsAliyunTestsModule.cs new file mode 100644 index 0000000000..6213ef160a --- /dev/null +++ b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AbpSmsAliyunTestsModule.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Sms.Aliyun +{ + [DependsOn(typeof(AbpSmsAliyunModule))] + public class AbpSmsAliyunTestsModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure( + configuration.GetSection("AbpAliyunSms") + ); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AliyunSmsSender_Tests.cs b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AliyunSmsSender_Tests.cs new file mode 100644 index 0000000000..1007e78afb --- /dev/null +++ b/framework/test/Volo.Abp.Sms.Aliyun.Tests/Volo/Abp/Sms/Aliyun/AliyunSmsSender_Tests.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Xunit; + +namespace Volo.Abp.Sms.Aliyun +{ + public class AliyunSmsSender_Tests : AbpSmsAliyunTestBase + { + private readonly ISmsSender _smsSender; + private readonly IConfiguration _configuration; + + public AliyunSmsSender_Tests() + { + _configuration = GetRequiredService(); + _smsSender = GetRequiredService(); + } + + [Fact] + public async Task SendSms_Test() + { + var config = _configuration.GetSection("AbpAliyunSms"); + + // Please fill in the real parameters in the appsettings.json file. + if (config["AccessKeyId"] == "") + { + return; + } + + var msg = new SmsMessage(config["TargetPhoneNumber"], + config["TemplateParam"]); + msg.Properties.Add("SignName", config["SignName"]); + msg.Properties.Add("TemplateCode", config["TemplateCode"]); + + await _smsSender.SendAsync(msg); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Sms.Aliyun.Tests/appsettings.json b/framework/test/Volo.Abp.Sms.Aliyun.Tests/appsettings.json new file mode 100644 index 0000000000..c4370a2928 --- /dev/null +++ b/framework/test/Volo.Abp.Sms.Aliyun.Tests/appsettings.json @@ -0,0 +1,11 @@ +{ + "AbpAliyunSms": { + "AccessKeySecret": "", + "AccessKeyId": "", + "EndPoint": "", + "TargetPhoneNumber": "", + "SignName": "", + "TemplateCode": "", + "TemplateParam": "" + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogDto.cs index 2e43db655c..e992ae8b1d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogDto.cs @@ -1,20 +1,13 @@ using System; -using System.ComponentModel.DataAnnotations; using Volo.Abp.Application.Dtos; -using Volo.Abp.Validation; -using Volo.CmsKit.Blogs; namespace Volo.CmsKit.Admin.Blogs { [Serializable] public class BlogDto : EntityDto { - [Required] - [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] public string Name { get; set; } - [Required] - [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] public string Slug { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogDto.cs new file mode 100644 index 0000000000..985567b48e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Admin.Blogs +{ + public class CreateBlogDto + { + [Required] + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] + public string Name { get; set; } + + [Required] + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] + public string Slug { get; set; } + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs index 3544b3d7af..6d82e6117c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs @@ -3,7 +3,7 @@ using Volo.Abp.Application.Services; namespace Volo.CmsKit.Admin.Blogs { - public interface IBlogAdminAppService : ICrudAppService + public interface IBlogAdminAppService : ICrudAppService { } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogDto.cs new file mode 100644 index 0000000000..832c1b7214 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Admin.Blogs +{ + public class UpdateBlogDto + { + [Required] + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] + public string Name { get; set; } + + [Required] + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] + public string Slug { get; set; } + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs index 5c833f5256..574f6f737a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs @@ -1,10 +1,8 @@ using Microsoft.AspNetCore.Authorization; using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; -using Volo.Abp.Application.Services; -using Volo.Abp.Domain.Repositories; +using Volo.Abp.Application.Dtos; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; using Volo.CmsKit.GlobalFeatures; @@ -14,24 +12,63 @@ namespace Volo.CmsKit.Admin.Blogs { [RequiresGlobalFeature(typeof(BlogsFeature))] [Authorize(CmsKitAdminPermissions.Blogs.Default)] - public class BlogAdminAppService : CrudAppService, IBlogAdminAppService + public class BlogAdminAppService : CmsKitAdminAppServiceBase, IBlogAdminAppService { - public BlogAdminAppService(IRepository repository) : base(repository) + protected IBlogRepository BlogRepository { get; } + protected BlogManager BlogManager { get; } + + public BlogAdminAppService(IBlogRepository blogRepository, BlogManager blogManager) { - GetListPolicyName = CmsKitAdminPermissions.Blogs.Default; - GetPolicyName = CmsKitAdminPermissions.Blogs.Default; - CreatePolicyName = CmsKitAdminPermissions.Blogs.Create; - UpdatePolicyName = CmsKitAdminPermissions.Blogs.Update; - DeletePolicyName = CmsKitAdminPermissions.Blogs.Delete; + BlogRepository = blogRepository; + BlogManager = blogManager; + } + + public virtual async Task GetAsync(Guid id) + { + var blog = await BlogRepository.GetAsync(id); + + return ObjectMapper.Map(blog); + } + + public virtual async Task> GetListAsync(BlogGetListInput input) + { + var totalCount = await BlogRepository.GetCountAsync(input.Filter); + + var blogs = await BlogRepository.GetListAsync( + input.Filter, + input.Sorting, + input.MaxResultCount, + input.SkipCount); + + return new PagedResultDto(totalCount, ObjectMapper.Map, List>(blogs)); + } + + [Authorize(CmsKitAdminPermissions.Blogs.Create)] + public virtual async Task CreateAsync(CreateBlogDto input) + { + var blog = await BlogManager.CreateAsync(input.Name, input.Slug); + + await BlogRepository.InsertAsync(blog); + + return ObjectMapper.Map(blog); + } + + [Authorize(CmsKitAdminPermissions.Blogs.Update)] + public virtual async Task UpdateAsync(Guid id, UpdateBlogDto input) + { + var blog = await BlogRepository.GetAsync(id); + + blog = await BlogManager.UpdateAsync(blog, input.Name, input.Slug); + + await BlogRepository.UpdateAsync(blog); + + return ObjectMapper.Map(blog); } - protected override async Task> CreateFilteredQueryAsync(BlogGetListInput input) + [Authorize(CmsKitAdminPermissions.Blogs.Delete)] + public virtual Task DeleteAsync(Guid id) { - var queryable = await base.CreateFilteredQueryAsync(input); - return queryable - .WhereIf( - !input.Filter.IsNullOrWhiteSpace(), - x => x.Name.ToLower().Contains(input.Filter)); + return BlogRepository.DeleteAsync(id); } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs index e31b3d9a25..b78910ce01 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs @@ -37,8 +37,7 @@ namespace Volo.CmsKit.Admin CreateMap(MemberList.Source); CreateMap(MemberList.Source); - CreateMap(MemberList.Destination) - .ReverseMap(); + CreateMap(); CreateMap(MemberList.Destination); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs index dfa8a00ea3..cf3de19933 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs @@ -8,15 +8,15 @@ namespace Volo.CmsKit.Admin.Tags public class EntityTagAdminAppService : CmsKitAdminAppServiceBase, IEntityTagAdminAppService { protected ITagDefinitionStore TagDefinitionStore { get; } - protected IEntityTagManager EntityTagManager { get; } - protected ITagManager TagManager { get; } + protected EntityTagManager EntityTagManager { get; } + protected TagManager TagManager { get; } protected ITagRepository TagRepository { get; } protected IEntityTagRepository EntityTagRepository { get; } public EntityTagAdminAppService( ITagDefinitionStore tagDefinitionStore, - IEntityTagManager entityTagManager, - ITagManager tagManager, + EntityTagManager entityTagManager, + TagManager tagManager, ITagRepository tagRepository, IEntityTagRepository entityTagRepository) { @@ -29,11 +29,11 @@ namespace Volo.CmsKit.Admin.Tags public virtual async Task AddTagToEntityAsync(EntityTagCreateDto input) { - var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType); + var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); await CheckPolicyAsync(definition.CreatePolicy); - var tag = await TagManager.GetOrAddAsync(input.EntityType, input.TagName, CurrentTenant?.Id); + var tag = await TagManager.GetOrAddAsync(input.EntityType, input.TagName); await EntityTagManager.AddTagToEntityAsync( tag.Id, @@ -44,7 +44,7 @@ namespace Volo.CmsKit.Admin.Tags public virtual async Task RemoveTagFromEntityAsync(EntityTagRemoveDto input) { - var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType); + var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); await CheckPolicyAsync(definition.DeletePolicy); @@ -57,24 +57,11 @@ namespace Volo.CmsKit.Admin.Tags public virtual async Task SetEntityTagsAsync(EntityTagSetDto input) { - var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType); + var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); await CheckPolicyAsync(definition.UpdatePolicy); - var existingTags = - await TagRepository.GetAllRelatedTagsAsync(input.EntityType, input.EntityId, CurrentTenant?.Id); - - var deletedTags = existingTags.Where(x => !input.Tags.Contains(x.Name)).ToList(); - var addedTags = input.Tags.Where(x => !existingTags.Any(a => a.Name == x)); - - await EntityTagRepository.DeleteManyAsync(deletedTags.Select(s => s.Id).ToArray()); - - foreach (var addedTag in addedTags) - { - var tag = await TagManager.GetOrAddAsync(input.EntityType, addedTag, CurrentTenant?.Id); - - await EntityTagManager.AddTagToEntityAsync(tag.Id, input.EntityType, input.EntityId, CurrentTenant?.Id); - } + await EntityTagManager.SetEntityTagsAsync(input.EntityType, input.EntityId, input.Tags); } } -} \ No newline at end of file +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs index 1120312466..5d4a9b03e0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs @@ -22,17 +22,19 @@ namespace Volo.CmsKit.Admin.Tags TagUpdateDto>, ITagAdminAppService { - protected ITagManager TagManager { get; } - + protected TagManager TagManager { get; } + protected ITagDefinitionStore TagDefinitionStore { get; } protected IStringLocalizerFactory StringLocalizerFactory { get; } public TagAdminAppService( IRepository repository, - ITagManager tagManager, + TagManager tagManager, + ITagDefinitionStore tagDefinitionStore, IStringLocalizerFactory stringLocalizerFactory) : base(repository) { TagManager = tagManager; - StringLocalizerFactory = stringLocalizerFactory; + TagDefinitionStore = tagDefinitionStore; + StringLocalizerFactory = stringLocalizerFactory; GetListPolicyName = CmsKitAdminPermissions.Tags.Default; GetPolicyName = CmsKitAdminPermissions.Tags.Default; @@ -44,12 +46,13 @@ namespace Volo.CmsKit.Admin.Tags [Authorize(CmsKitAdminPermissions.Tags.Create)] public override async Task CreateAsync(TagCreateDto input) { - var tag = await TagManager.InsertAsync( + var tag = await TagManager.CreateAsync( GuidGenerator.Create(), input.EntityType, - input.Name, - CurrentTenant?.Id); - + input.Name); + + await Repository.InsertAsync(tag); + return await MapToGetOutputDtoAsync(tag); } @@ -60,11 +63,14 @@ namespace Volo.CmsKit.Admin.Tags id, input.Name); + await Repository.UpdateAsync(tag); + return await MapToGetOutputDtoAsync(tag); } - protected override IQueryable CreateFilteredQuery(TagGetListInput input) + + protected override async Task> CreateFilteredQueryAsync(TagGetListInput input) { - return base.CreateFilteredQuery(input) + return (await base.CreateFilteredQueryAsync(input)) .WhereIf( !input.Filter.IsNullOrEmpty(), x => @@ -74,7 +80,7 @@ namespace Volo.CmsKit.Admin.Tags public virtual async Task> GetTagDefinitionsAsync() { - var definitions = await TagManager.GetTagDefinitionsAsync(); + var definitions = await TagDefinitionStore.GetTagEntityTypeDefinitionListAsync(); return definitions .Select(s => diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs index da565413b1..5e8067ed6f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs @@ -1,9 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Application.Dtos; @@ -27,42 +24,40 @@ namespace Volo.CmsKit.Admin.Blogs BlogAdminAppService = blogAdminAppService; } - [HttpPost] - [Authorize(CmsKitAdminPermissions.Blogs.Create)] - public Task CreateAsync(BlogDto input) - { - return BlogAdminAppService.CreateAsync(input); - } - - [HttpDelete] - [Route("{id}")] - [Authorize(CmsKitAdminPermissions.Blogs.Delete)] - public Task DeleteAsync(Guid id) - { - return BlogAdminAppService.DeleteAsync(id); - } - [HttpGet] [Route("{id}")] - [Authorize(CmsKitAdminPermissions.Blogs.Default)] public Task GetAsync(Guid id) { return BlogAdminAppService.GetAsync(id); } [HttpGet] - [Authorize(CmsKitAdminPermissions.Blogs.Default)] - public Task> GetListAsync([FromQuery] BlogGetListInput input) + public Task> GetListAsync(BlogGetListInput input) { return BlogAdminAppService.GetListAsync(input); } + + [HttpPost] + [Authorize(CmsKitAdminPermissions.Blogs.Create)] + public Task CreateAsync(CreateBlogDto input) + { + return BlogAdminAppService.CreateAsync(input); + } [HttpPut] [Route("{id}")] [Authorize(CmsKitAdminPermissions.Blogs.Update)] - public Task UpdateAsync(Guid id, BlogDto input) + public Task UpdateAsync(Guid id, UpdateBlogDto input) { return BlogAdminAppService.UpdateAsync(id, input); } + + [HttpDelete] + [Route("{id}")] + [Authorize(CmsKitAdminPermissions.Blogs.Delete)] + public Task DeleteAsync(Guid id) + { + return BlogAdminAppService.DeleteAsync(id); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs index 61dfb15571..191eeb4999 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs @@ -20,8 +20,7 @@ namespace Volo.CmsKit.Tags { var entities = await TagRepository.GetAllRelatedTagsAsync( entityType, - entityId, - CurrentTenant.Id); + entityId); return ObjectMapper.Map, List>(entities); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs index 3251bcb230..64956b8683 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs @@ -16,6 +16,11 @@ } public static class Blogs + { + public const string SlugAlreadyExists = "CmsKit:Blog:0001"; + } + + public static class BlogPosts { public const string SlugAlreadyExist = "CmsKit:BlogPost:0001"; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index 45e2e56a9b..212d495459 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -3,6 +3,7 @@ "texts": { "CmsKit:0002": "Content already exists!", "CmsKit:0003": "The entity {0} is not taggable.", + "CmsKit:Blog:0001": "The given slug ({Slug}) already exists!", "CmsKit:BlogPost:0001": "The given slug already exists!", "CmsKit:Media:0001": "'{Name}' is not a valid media name.", "CmsKit:Page:0001": "The given url ({0}) already exists.", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs index 832ed4385e..313b282a1f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs @@ -9,17 +9,6 @@ namespace Volo.CmsKit.Blogs { public class Blog : FullAuditedAggregateRoot, IMultiTenant { - public Blog( - Guid id, - [NotNull] string name, - [NotNull] string slug, - [CanBeNull] Guid? tenantId = null) : base(id) - { - SetName(name); - SetSlug(slug); - TenantId = tenantId; - } - [NotNull] public virtual string Name { get; protected set; } @@ -27,15 +16,22 @@ namespace Volo.CmsKit.Blogs public virtual string Slug { get; protected set; } public virtual Guid? TenantId { get; protected set; } - + + protected internal Blog(Guid id, [NotNull] string name, [NotNull] string slug, [CanBeNull] Guid? tenantId = null) : base(id) + { + SetName(name); + SetSlug(slug); + TenantId = tenantId; + } + public virtual void SetName(string name) { - Name = Check.NotNullOrWhiteSpace(name, nameof(name), maxLength: BlogConsts.MaxNameLength); + Name = Check.NotNullOrWhiteSpace(name, nameof(name), BlogConsts.MaxNameLength); } public virtual void SetSlug(string slug) { - Check.NotNullOrWhiteSpace(slug, nameof(slug), maxLength: BlogConsts.MaxNameLength); + Check.NotNullOrWhiteSpace(slug, nameof(slug), BlogConsts.MaxNameLength); Slug = slug.NormalizeSlug(); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogManager.cs new file mode 100644 index 0000000000..1d2e2f5b07 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogManager.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Domain.Services; + +namespace Volo.CmsKit.Blogs +{ + public class BlogManager : DomainService + { + protected IBlogRepository BlogRepository { get; } + + public BlogManager(IBlogRepository blogRepository) + { + BlogRepository = blogRepository; + } + + public virtual async Task CreateAsync([NotNull] string name, [NotNull] string slug) + { + await CheckSlugAsync(slug); + + return new Blog(GuidGenerator.Create(), name, slug, CurrentTenant.Id); + } + + public virtual async Task UpdateAsync([NotNull] Blog blog, [NotNull] string name, [NotNull] string slug) + { + if (slug != blog.Slug) + { + await CheckSlugAsync(slug); + } + + blog.SetName(name); + blog.SetSlug(slug); + + return blog; + } + + protected virtual async Task CheckSlugAsync([NotNull] string slug) + { + if (await BlogRepository.SlugExistsAsync(slug)) + { + throw new BlogSlugAlreadyExistException(slug); + } + } + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostSlugAlreadyExistException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostSlugAlreadyExistException.cs index 034cb8e60d..a2cdf68f39 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostSlugAlreadyExistException.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostSlugAlreadyExistException.cs @@ -19,7 +19,7 @@ namespace Volo.CmsKit.Blogs Slug = slug; BlogId = blogId; - Code = CmsKitErrorCodes.Blogs.SlugAlreadyExist; + Code = CmsKitErrorCodes.BlogPosts.SlugAlreadyExist; WithData(nameof(Slug), Slug); WithData(nameof(BlogId), BlogId); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogSlugAlreadyExistException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogSlugAlreadyExistException.cs new file mode 100644 index 0000000000..e50f2f623c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogSlugAlreadyExistException.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.Serialization; +using Volo.Abp; + +namespace Volo.CmsKit.Blogs +{ + [Serializable] + public class BlogSlugAlreadyExistException : BusinessException + { + public BlogSlugAlreadyExistException(string slug) + { + Code = CmsKitErrorCodes.Blogs.SlugAlreadyExists; + + WithData(nameof(Blog.Slug), slug); + } + + public BlogSlugAlreadyExistException( + SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) + { + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs index 2feb057111..b340b9e256 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/IBlogRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -7,7 +8,23 @@ namespace Volo.CmsKit.Blogs { public interface IBlogRepository : IBasicRepository { - public Task GetBySlugAsync(string slug, CancellationToken cancellationToken = default); - Task ExistsAsync(Guid blogId, CancellationToken cancellationToken = default); + Task> GetListAsync( + string filter = null, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + CancellationToken cancellationToken = default + ); + + Task GetCountAsync( + string filter = null, + CancellationToken cancellationToken = default + ); + + Task GetBySlugAsync(string slug, CancellationToken cancellationToken = default); + + Task ExistsAsync(Guid id, CancellationToken cancellationToken = default); + + Task SlugExistsAsync(string slug, CancellationToken cancellationToken = default); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs index 1119219e1b..3829a3afef 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs @@ -33,7 +33,7 @@ namespace Volo.CmsKit.MediaDescriptors public void SetName(string name) { - if (!name.IsValidMediaFileName()) + if (!MediaDescriptorCheck.IsValidMediaFileName(name)) { throw new InvalidMediaDescriptorNameException(name); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/Extensions/MediaDescriptorExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorCheck.cs similarity index 72% rename from modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/Extensions/MediaDescriptorExtensions.cs rename to modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorCheck.cs index a8a8e6545d..5ef0c4497a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/Extensions/MediaDescriptorExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorCheck.cs @@ -3,9 +3,9 @@ using System.Linq; namespace Volo.CmsKit.MediaDescriptors.Extensions { - public static class MediaDescriptorExtensions + public static class MediaDescriptorCheck { - public static bool IsValidMediaFileName(this string name) + public static bool IsValidMediaFileName(string name) { if (string.IsNullOrWhiteSpace(name)) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/CmsKitTagOptions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/CmsKitTagOptions.cs index e6530c887a..1b21af2417 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/CmsKitTagOptions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/CmsKitTagOptions.cs @@ -5,6 +5,6 @@ namespace Volo.CmsKit.Tags public class CmsKitTagOptions { [NotNull] - public TagEntityTypeDefinitionDictionary EntityTypes { get; } = new TagEntityTypeDefinitionDictionary(); + public TagEntityTypeDefinitions EntityTypes { get; } = new TagEntityTypeDefinitions(); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs index 1787b2b949..dc804d0417 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs @@ -24,7 +24,7 @@ namespace Volo.CmsKit.Tags /// EntityType to get definition. /// Thrown when EntityType is not configured as taggable. /// More than one element satisfies the condition in predicate. - public virtual Task GetTagEntityTypeDefinitionsAsync([NotNull] string entityType) + public virtual Task GetTagEntityTypeDefinitionAsync([NotNull] string entityType) { Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityNotTaggableException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityNotTaggableException.cs index 8787fb16a5..c73549f4a5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityNotTaggableException.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityNotTaggableException.cs @@ -1,5 +1,5 @@ -using Microsoft.Extensions.Logging; -using System; +using System; +using System.Runtime.Serialization; using Volo.Abp; namespace Volo.CmsKit.Tags @@ -7,13 +7,7 @@ namespace Volo.CmsKit.Tags [Serializable] public class EntityNotTaggableException : BusinessException { - public EntityNotTaggableException( - string code = null, - string message = null, - string details = null, - Exception innerException = null, - LogLevel logLevel = LogLevel.Warning) - : base(code, message, details, innerException, logLevel) + public EntityNotTaggableException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) { } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs index ad7a3088d5..97a2e7cd74 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs @@ -1,22 +1,30 @@ using JetBrains.Annotations; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Services; namespace Volo.CmsKit.Tags { - public class EntityTagManager : DomainService, IEntityTagManager + public class EntityTagManager : DomainService { protected IEntityTagRepository EntityTagRepository { get; } + protected ITagRepository TagRepository { get; } protected ITagDefinitionStore TagDefinitionStore { get; } + protected TagManager TagManager { get; } public EntityTagManager( IEntityTagRepository entityTagRepository, - ITagDefinitionStore tagDefinitionStore) + ITagRepository tagRepository, + ITagDefinitionStore tagDefinitionStore, + TagManager tagManager) { EntityTagRepository = entityTagRepository; + TagRepository = tagRepository; TagDefinitionStore = tagDefinitionStore; + TagManager = tagManager; } public virtual async Task AddTagToEntityAsync( @@ -45,5 +53,23 @@ namespace Volo.CmsKit.Tags var entityTag = await EntityTagRepository.FindAsync(tagId, entityId, tenantId, cancellationToken); await EntityTagRepository.DeleteAsync(entityTag, cancellationToken: cancellationToken); } + + public async Task SetEntityTagsAsync(string entityType, string entityId, List tags) + { + var existingTags = + await TagRepository.GetAllRelatedTagsAsync(entityType, entityId); + + var deletedTags = existingTags.Where(x => !tags.Contains(x.Name)).ToList(); + var addedTags = tags.Where(x => !existingTags.Any(a => a.Name == x)); + + await EntityTagRepository.DeleteManyAsync(deletedTags.Select(s => s.Id).ToArray()); + + foreach (var addedTag in addedTags) + { + var tag = await TagManager.GetOrAddAsync(entityType, addedTag); + + await AddTagToEntityAsync(tag.Id, entityType, entityId, CurrentTenant?.Id); + } + } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagManager.cs deleted file mode 100644 index 704568619a..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagManager.cs +++ /dev/null @@ -1,24 +0,0 @@ -using JetBrains.Annotations; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Volo.CmsKit.Tags -{ - public interface IEntityTagManager - { - Task AddTagToEntityAsync( - [NotNull] Guid tagId, - [NotNull] string entityType, - [NotNull] string entityId, - [CanBeNull] Guid? tenantId = null, - CancellationToken cancellationToken = default); - - Task RemoveTagFromEntityAsync( - [NotNull] Guid tagId, - [NotNull] string entityType, - [NotNull] string entityId, - [CanBeNull] Guid? tenantId = null, - CancellationToken cancellationToken = default); - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs index 1dd8ae2bc3..906cb2b3e4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs @@ -8,7 +8,7 @@ namespace Volo.CmsKit.Tags { Task> GetTagEntityTypeDefinitionListAsync(); - Task GetTagEntityTypeDefinitionsAsync([NotNull] string entityType); + Task GetTagEntityTypeDefinitionAsync([NotNull] string entityType); Task IsDefinedAsync([NotNull] string entityType); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagManager.cs deleted file mode 100644 index 4b9cef5fb8..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagManager.cs +++ /dev/null @@ -1,33 +0,0 @@ -using JetBrains.Annotations; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Services; -using Volo.CmsKit.Tags; - -namespace Volo.CmsKit.Tags -{ - public interface ITagManager : IDomainService - { - Task InsertAsync( - Guid id, - [NotNull] string entityType, - [NotNull] string name, - Guid? tenantId = null, - CancellationToken cancellationToken = default); - - Task UpdateAsync( - Guid id, - [NotNull] string name, - CancellationToken cancellationToken = default); - - Task GetOrAddAsync( - [NotNull] string entityType, - [NotNull] string name, - Guid? tenantId = null, - CancellationToken cancellationToken = default); - - Task> GetTagDefinitionsAsync(CancellationToken cancellationToken = default); - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs index 8493fe8401..b45bd30db7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs @@ -12,25 +12,21 @@ namespace Volo.CmsKit.Tags Task GetAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default); Task AnyAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default); Task FindAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default); Task> GetAllRelatedTagsAsync( [NotNull] string entityType, [NotNull] string entityId, - Guid? tenantId = null, CancellationToken cancellationToken = default); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitionDictionary.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitionDictionary.cs deleted file mode 100644 index 888ad15577..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitionDictionary.cs +++ /dev/null @@ -1,11 +0,0 @@ -using JetBrains.Annotations; -using System; -using System.Collections.Generic; -using Volo.Abp.Localization; - -namespace Volo.CmsKit.Tags -{ - public class TagEntityTypeDefinitionDictionary : List - { - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitions.cs new file mode 100644 index 0000000000..e0d15f82fa --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitions.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.CmsKit.Tags +{ + public class TagEntityTypeDefinitions : List + { + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagManager.cs index 94a3784bcd..d1378bccb7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagManager.cs @@ -3,11 +3,12 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Volo.Abp; using Volo.Abp.Domain.Services; namespace Volo.CmsKit.Tags { - public class TagManager : DomainService, ITagManager + public class TagManager : DomainService { protected ITagRepository TagRepository { get; } protected ITagDefinitionStore TagDefinitionStore { get; } @@ -18,56 +19,52 @@ namespace Volo.CmsKit.Tags TagDefinitionStore = tagDefinitionStore; } - public virtual async Task GetOrAddAsync([NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) + public virtual async Task GetOrAddAsync([NotNull] string entityType, [NotNull] string name) { - var entity = await TagRepository.FindAsync(entityType, name, tenantId, cancellationToken); + var tag = await TagRepository.FindAsync(entityType, name); - if (entity == null) + if (tag == null) { - entity = await InsertAsync(GuidGenerator.Create(), entityType, name, tenantId, cancellationToken); + tag = await CreateAsync(GuidGenerator.Create(), entityType, name); + await TagRepository.InsertAsync(tag); } - return entity; + return tag; } - public virtual async Task InsertAsync(Guid id, [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) + public virtual async Task CreateAsync(Guid id, + [NotNull] string entityType, + [NotNull] string name) { if (!await TagDefinitionStore.IsDefinedAsync(entityType)) { throw new EntityNotTaggableException(entityType); } - if (await TagRepository.AnyAsync(entityType, name, tenantId, cancellationToken)) + if (await TagRepository.AnyAsync(entityType, name)) { throw new TagAlreadyExistException(entityType, name); } - return await TagRepository.InsertAsync(new Tag(id, entityType, name, tenantId), - cancellationToken: cancellationToken); + return + new Tag(id, entityType, name, CurrentTenant.Id); } - public virtual async Task UpdateAsync(Guid id, [NotNull] string name, - CancellationToken cancellationToken = default) + public virtual async Task UpdateAsync(Guid id, [NotNull] string name) { - var entity = await TagRepository.GetAsync(id, cancellationToken: cancellationToken); + Check.NotNullOrEmpty(name, nameof(name)); - if (name != entity.Name && - await TagRepository.AnyAsync(entity.EntityType, name, entity.TenantId, cancellationToken)) + var tag = await TagRepository.GetAsync(id); + + if (name != tag.Name && + await TagRepository.AnyAsync(tag.EntityType, name)) { - throw new TagAlreadyExistException(entity.EntityType, name); + throw new TagAlreadyExistException(tag.EntityType, name); } - entity.SetName(name); - - return await TagRepository.UpdateAsync(entity, cancellationToken: cancellationToken); - } + tag.SetName(name); - public virtual Task> GetTagDefinitionsAsync( - CancellationToken cancellationToken = default) - { - return TagDefinitionStore.GetTagEntityTypeDefinitionListAsync(); + return tag; } } -} \ No newline at end of file +} diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs index c39dee2685..bfcb6d3cab 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Blogs/EfCoreBlogRepository.cs @@ -1,9 +1,11 @@ -using Microsoft.EntityFrameworkCore; -using System; -using System.Security.Cryptography.X509Certificates; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; using Volo.Abp; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -17,15 +19,47 @@ namespace Volo.CmsKit.Blogs { } - public virtual async Task ExistsAsync(Guid blogId, CancellationToken cancellationToken = default) + public virtual async Task ExistsAsync(Guid id, CancellationToken cancellationToken = default) { - return await (await GetQueryableAsync()).AnyAsync(x => x.Id == blogId, GetCancellationToken(cancellationToken)); + return await (await GetQueryableAsync()).AnyAsync(x => x.Id == id, GetCancellationToken(cancellationToken)); } - public virtual Task GetBySlugAsync([NotNull]string slug, CancellationToken cancellationToken = default) + public virtual async Task SlugExistsAsync(string slug, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).AnyAsync(x => x.Slug == slug, GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetListAsync( + string filter = null, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + var query = await GetListQueryAsync(filter); + + return await query.OrderBy(sorting ?? "creationTime desc") + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task GetCountAsync(string filter = null, CancellationToken cancellationToken = default) + { + var query = await GetListQueryAsync(filter); + + return await query.LongCountAsync(GetCancellationToken(cancellationToken)); + } + + public virtual Task GetBySlugAsync([NotNull] string slug, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(slug, nameof(slug)); return GetAsync(x => x.Slug == slug, cancellationToken: GetCancellationToken(cancellationToken)); } + + protected virtual async Task> GetListQueryAsync(string filter = null) + { + return (await GetDbSetAsync()) + .WhereIf(!filter.IsNullOrWhiteSpace(), b => b.Name.Contains(filter)); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs index 7325141c40..bc33e4f660 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs @@ -21,7 +21,6 @@ namespace Volo.CmsKit.Tags public virtual async Task AnyAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(entityType, nameof(entityType)); @@ -29,15 +28,13 @@ namespace Volo.CmsKit.Tags return await (await GetDbSetAsync()).AnyAsync(x => x.EntityType == entityType && - x.Name == name && - x.TenantId == tenantId, + x.Name == name, GetCancellationToken(cancellationToken)); } public virtual Task GetAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(entityType, nameof(entityType)); @@ -45,15 +42,13 @@ namespace Volo.CmsKit.Tags return GetAsync(x => x.EntityType == entityType && - x.Name == name && - x.TenantId == tenantId, + x.Name == name, cancellationToken: GetCancellationToken(cancellationToken)); } public virtual Task FindAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(entityType, nameof(entityType)); @@ -61,28 +56,25 @@ namespace Volo.CmsKit.Tags return FindAsync(x => x.EntityType == entityType && - x.Name == name && - x.TenantId == tenantId, + x.Name == name, cancellationToken: GetCancellationToken(cancellationToken)); } public virtual async Task> GetAllRelatedTagsAsync( [NotNull] string entityType, [NotNull] string entityId, - Guid? tenantId = null, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(entityId, nameof(entityId)); var entityTagIds = await (await GetDbContextAsync()).Set() - .Where(q => q.EntityId == entityId && q.TenantId == tenantId) + .Where(q => q.EntityId == entityId) .Select(q => q.TagId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); var query = (await GetDbSetAsync()) .Where(x => x.EntityType == entityType && - x.TenantId == tenantId && entityTagIds.Contains(x.Id)); return await query.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs index 0cd46a130c..32119610bb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs @@ -1,8 +1,12 @@ -using MongoDB.Driver.Core.Operations; -using System; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; +using MongoDB.Driver; +using MongoDB.Driver.Linq; using Volo.Abp; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; @@ -16,18 +20,54 @@ namespace Volo.CmsKit.MongoDB.Blogs { } - public virtual async Task ExistsAsync(Guid blogId, CancellationToken cancellationToken = default) + public virtual async Task ExistsAsync(Guid id, CancellationToken cancellationToken = default) { - return await AsyncExecuter.AnyAsync( - await GetQueryableAsync(), - x => x.Id == blogId, - cancellationToken); + var token = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(token)).AnyAsync(x => x.Id == id, token); } - public virtual Task GetBySlugAsync([NotNull]string slug, CancellationToken cancellationToken = default) + public virtual async Task SlugExistsAsync(string slug, CancellationToken cancellationToken = default) + { + var token = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(token)).AnyAsync(x => x.Slug == slug, token); + } + + public virtual async Task> GetListAsync( + string filter = null, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + var token = GetCancellationToken(cancellationToken); + + var query = await GetListQueryAsync(filter, token); + + return await query.OrderBy(sorting ?? "creationTime desc") + .As>() + .PageBy>(skipCount, maxResultCount) + .ToListAsync(token); + } + + public virtual async Task GetCountAsync(string filter = null, CancellationToken cancellationToken = default) + { + var token = GetCancellationToken(cancellationToken); + + var query = await GetListQueryAsync(filter, token); + + return await query.As>().LongCountAsync(token); + } + + public virtual Task GetBySlugAsync([NotNull] string slug, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(slug, nameof(slug)); return GetAsync(x => x.Slug == slug, cancellationToken: cancellationToken); } + + protected virtual async Task> GetListQueryAsync(string filter = null, CancellationToken cancellationToken = default) + { + return (await GetMongoQueryableAsync(GetCancellationToken(cancellationToken))) + .WhereIf(!filter.IsNullOrWhiteSpace(), b => b.Name.Contains(filter)); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs index 5e8fdf94a7..bb35a19075 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs @@ -22,7 +22,6 @@ namespace Volo.CmsKit.MongoDB.Tags public async Task AnyAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(entityType, nameof(entityType)); @@ -31,28 +30,24 @@ namespace Volo.CmsKit.MongoDB.Tags return await (await GetMongoQueryableAsync(cancellationToken)) .AnyAsync(x => x.EntityType == entityType && - x.Name == name && - x.TenantId == tenantId, + x.Name == name, GetCancellationToken(cancellationToken)); } public Task GetAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) { return GetAsync(x => x.EntityType == entityType && - x.Name == name && - x.TenantId == tenantId, + x.Name == name, cancellationToken: GetCancellationToken(cancellationToken)); } public Task FindAsync( [NotNull] string entityType, [NotNull] string name, - Guid? tenantId = null, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(entityType, nameof(entityType)); @@ -60,29 +55,26 @@ namespace Volo.CmsKit.MongoDB.Tags return FindAsync(x => x.EntityType == entityType && - x.Name == name && - x.TenantId == tenantId, + x.Name == name, cancellationToken: GetCancellationToken(cancellationToken)); } public virtual async Task> GetAllRelatedTagsAsync( [NotNull] string entityType, [NotNull] string entityId, - Guid? tenantId = null, CancellationToken cancellationToken = default) { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(entityId, nameof(entityId)); var entityTagIds = await (await GetDbContextAsync(cancellationToken)).EntityTags.AsQueryable() - .Where(q => q.EntityId == entityId && q.TenantId == tenantId) + .Where(q => q.EntityId == entityId) .Select(q => q.TagId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); var query = (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.EntityType == entityType && - x.TenantId == tenantId && entityTagIds.Contains(x.Id)); var result = await query.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogAdminAppService_Tests.cs new file mode 100644 index 0000000000..0f0e4ee2f8 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogAdminAppService_Tests.cs @@ -0,0 +1,92 @@ +using System.Linq; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Domain.Entities; +using Volo.CmsKit.Admin.Blogs; +using Xunit; + +namespace Volo.CmsKit.Blogs +{ + public class BlogAdminAppService_Tests : CmsKitApplicationTestBase + { + protected IBlogAdminAppService BlogAdminAppService { get; } + protected CmsKitTestData CmsKitTestData { get; } + protected IBlogRepository BlogRepository { get; } + + public BlogAdminAppService_Tests() + { + BlogAdminAppService = GetRequiredService(); + CmsKitTestData = GetRequiredService(); + BlogRepository = GetRequiredService(); + } + + [Fact] + public async Task GetAsync() + { + var blog = await BlogAdminAppService.GetAsync(CmsKitTestData.Blog_Id); + + blog.Slug.ShouldBe(CmsKitTestData.BlogSlug); + } + + [Fact] + public async Task GetListAsync() + { + var blogs = await BlogAdminAppService.GetListAsync(new BlogGetListInput()); + + blogs.TotalCount.ShouldBeGreaterThan(0); + blogs.Items.Any(x => x.Slug == CmsKitTestData.BlogSlug).ShouldBeTrue(); + } + + [Fact] + public async Task CreateAsync_ShouldWork() + { + var blog = await BlogAdminAppService.CreateAsync(new CreateBlogDto + { + Name = "News", + Slug = "latest-news" + }); + + blog.ShouldNotBeNull(); + blog.Name.ShouldBe("News"); + blog.Slug.ShouldBe("latest-news"); + } + + [Fact] + public async Task CreateAsync_ShouldThrow_WithExistSlug() + { + await Should.ThrowAsync( + async () => + await BlogAdminAppService.CreateAsync(new CreateBlogDto + { + Name = "News", + Slug = CmsKitTestData.BlogSlug + })); + } + + [Fact] + public async Task UpdateAsync_ShouldWork() + { + var blog = await BlogAdminAppService.UpdateAsync(CmsKitTestData.Blog_Id, new UpdateBlogDto + { + Name = "New Name", + Slug = "new-slug" + }); + + var updatedBlog = await BlogAdminAppService.GetAsync(CmsKitTestData.Blog_Id); + + updatedBlog.Name.ShouldBe("New Name"); + updatedBlog.Slug.ShouldBe("new-slug"); + } + + [Fact] + public async Task DeleteAsync_ShouldWork() + { + await BlogAdminAppService.DeleteAsync(CmsKitTestData.Blog_Id); + + await Should.ThrowAsync( + async () => + await BlogAdminAppService.GetAsync(CmsKitTestData.Blog_Id) + ); + } + } +} \ No newline at end of file diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagAdminAppService_Tests.cs index b2128bb385..e621e87caa 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagAdminAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagAdminAppService_Tests.cs @@ -48,5 +48,15 @@ namespace Volo.CmsKit.Tags Name = _cmsKitTestData.Content_1_Tags[0], })); } + + public async Task GetTagDefinitionsAsync_ShouldWorkProperly_WithoutParameters() + { + var definitions = await _tagAdminAppService.GetTagDefinitionsAsync(); + + definitions.ShouldNotBeNull(); + definitions.ShouldNotBeEmpty(); + definitions.Count.ShouldBeGreaterThan(1); + definitions.ShouldContain(x => x.EntityType == _cmsKitTestData.TagDefinition_1_EntityType); + } } } diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/BlogManager_Test.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/BlogManager_Test.cs new file mode 100644 index 0000000000..a5b878d454 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Blogs/BlogManager_Test.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.CmsKit.Blogs +{ + public class BlogManager_Test : CmsKitDomainTestBase + { + protected IBlogRepository BlogRepository { get; } + protected BlogManager BlogManager { get; } + protected CmsKitTestData TestData { get; } + + public BlogManager_Test() + { + BlogRepository = GetRequiredService(); + BlogManager = GetRequiredService(); + TestData = GetRequiredService(); + } + + [Fact] + public async Task BlogCreate_ShouldThrowException_WithExistSlug() + { + await Should.ThrowAsync( + async () => + await BlogManager.CreateAsync("test-name", TestData.BlogSlug) + ); + } + + [Fact] + public async Task BlogCreate_ShouldWorkProperly() + { + var blog = await BlogManager.CreateAsync("test-name", "test-slug"); + + blog.ShouldNotBeNull(); + blog.Id.ShouldNotBe(Guid.Empty); + } + + [Fact] + public async Task BlogUpdate_ShouldWork() + { + var blog = await BlogRepository.GetAsync(TestData.Blog_Id); + + await BlogManager.UpdateAsync(blog, "New name", "new-slug"); + + blog.Name.ShouldBe("New name"); + blog.Slug.ShouldBe("new-slug"); + } + } +} \ No newline at end of file diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/EntityTagManager_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/EntityTagManager_Tests.cs index 5a6144733c..a39e6a1095 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/EntityTagManager_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/EntityTagManager_Tests.cs @@ -1,4 +1,5 @@ using Shouldly; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Volo.Abp.Guids; @@ -9,14 +10,14 @@ namespace Volo.CmsKit.Tags public class EntityTagManager_Tests : CmsKitDomainTestBase { private readonly CmsKitTestData _cmsKitTestData; - private readonly IEntityTagManager _entityTagManager; + private readonly EntityTagManager _entityTagManager; private readonly ITagRepository _tagRepository; private readonly IGuidGenerator _guidGenerator; public EntityTagManager_Tests() { _cmsKitTestData = GetRequiredService(); - _entityTagManager = GetRequiredService(); + _entityTagManager = GetRequiredService(); _tagRepository = GetRequiredService(); _guidGenerator = GetRequiredService(); } @@ -56,5 +57,54 @@ namespace Volo.CmsKit.Tags tags.ShouldNotContain(x => x.Id == tagToDelete.Id); } + + [Fact] + public async Task SetEntityTagsAsync_ShouldWorkProperly_WithNonExistingTags() + { + var newTags = new List { "non-existing-awesome-tag-a", "non-existing-awesome-tag-b" }; + + await _entityTagManager.SetEntityTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1, newTags); + + var tags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1); + + tags.ShouldNotBeNull(); + tags.ShouldNotBeEmpty(); + tags.ForEach(tag => newTags.Contains(tag.Name)); + } + + [Fact] + public async Task SetEntityTagsAsync_ShouldWorkProperly_WithExistingTag() + { + var entityTags = new List + { + _cmsKitTestData.TagName_1 + }; + + await _entityTagManager.SetEntityTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1, entityTags); + + var tags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1); + + tags.ShouldNotBeNull(); + tags.ShouldNotBeEmpty(); + tags.ForEach(tag => entityTags.Contains(tag.Name)); + } + + [Fact] + public async Task SetEntityTagsAsync_ShouldWorkProperly_WithExistingAndNonExistingTag() + { + var entityTags = new List + { + "New Awesome Tag", + _cmsKitTestData.TagName_1 + }; + + await _entityTagManager.SetEntityTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1, entityTags); + + var tags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1); + + tags.ShouldNotBeNull(); + tags.ShouldNotBeEmpty(); + tags.ForEach(tag => entityTags.Contains(tag.Name)); + } } } diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagManager_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagManager_Tests.cs index 7d7416c8ce..0aadc33caf 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagManager_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagManager_Tests.cs @@ -53,24 +53,23 @@ namespace Volo.CmsKit.Tags } [Fact] - public async Task ShouldInsertAsync() + public async Task ShouldCreateAsync() { var tagName = "Freshly Created New Tag"; - var tag = await _tagManager.InsertAsync(Guid.NewGuid(), _cmsKitTestData.EntityType1, tagName); + var tag = await _tagManager.CreateAsync(Guid.NewGuid(), _cmsKitTestData.EntityType1, tagName); tag.ShouldNotBeNull(); - var doesExist = await _tagRepository.AnyAsync(_cmsKitTestData.EntityType1, tagName); - - doesExist.ShouldBeTrue(); + tag.Id.ShouldNotBe(Guid.Empty); } + [Fact] public async Task ShouldntInsertWithUnconfiguredEntityTypeAsync() { var notConfiguredEntityType = "My.Namespace.SomeEntity"; var exception = await Should.ThrowAsync(async () => - await _tagManager.InsertAsync(Guid.NewGuid(), notConfiguredEntityType, "test")); + await _tagManager.CreateAsync(Guid.NewGuid(), notConfiguredEntityType, "test")); exception.ShouldNotBeNull(); exception.Data[nameof(Tag.EntityType)].ShouldBe(notConfiguredEntityType); @@ -82,7 +81,7 @@ namespace Volo.CmsKit.Tags var type = _cmsKitTestData.Content_1_EntityType; var name = _cmsKitTestData.Content_1_Tags[0]; - Should.Throw(async () => await _tagManager.InsertAsync(Guid.NewGuid(), type, name)); + Should.Throw(async () => await _tagManager.CreateAsync(Guid.NewGuid(), type, name)); } [Fact] @@ -94,11 +93,10 @@ namespace Volo.CmsKit.Tags var tag = await _tagRepository.GetAsync(type, name); - await _tagManager.UpdateAsync(tag.Id, newName); - - var updatedTag = await _tagRepository.GetAsync(type, newName); + var updatedTag = await _tagManager.UpdateAsync(tag.Id, newName); updatedTag.Id.ShouldBe(tag.Id); + updatedTag.Name.ShouldBe(newName); } [Fact] @@ -112,15 +110,5 @@ namespace Volo.CmsKit.Tags Should.Throw(async () => await _tagManager.UpdateAsync(tag.Id, newName)); } - - [Fact] - public async Task ShouldGetTagDefinitionsProperly_WithoutParameter() - { - var definitions = await _tagManager.GetTagDefinitionsAsync(); - - definitions.ShouldNotBeNull(); - definitions.Count.ShouldBeGreaterThan(1); - definitions.ShouldContain(x => x.EntityType == _cmsKitTestData.TagDefinition_1_EntityType); - } } } \ No newline at end of file diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs index 50a99519eb..6d4fcd59fd 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Blogs/BlogRepository_Test.cs @@ -61,5 +61,32 @@ namespace Volo.CmsKit.Blogs result.ShouldBeFalse(); } + + [Fact] + public async Task GetList_ShouldWorkProperly() + { + var list = await blogRepository.GetListAsync(); + + list.ShouldNotBeNull(); + list.Count.ShouldBeGreaterThan(0); + } + + [Fact] + public async Task GetCount_ShouldWorkProperly() + { + var count = await blogRepository.GetCountAsync(); + + count.ShouldBeGreaterThan(0); + } + + [Fact] + public async Task SlugExistAsync_ShouldWorkProperly() + { + var exists = await blogRepository.SlugExistsAsync(testData.BlogSlug); + var notExists = await blogRepository.SlugExistsAsync("not-existing-blog-slug"); + + exists.ShouldBeTrue(); + notExists.ShouldBeFalse(); + } } } diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs index a6f4b10aa8..f07460edc8 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs @@ -34,8 +34,9 @@ namespace Volo.CmsKit private readonly IRatingRepository _ratingRepository; private readonly ICurrentTenant _currentTenant; private readonly IContentRepository _contentRepository; - private readonly IEntityTagManager _entityTagManager; - private readonly ITagManager _tagManager; + private readonly EntityTagManager _entityTagManager; + private readonly TagManager _tagManager; + private readonly ITagRepository _tagRepository; private readonly IEntityTagRepository _entityTagRepository; private readonly IPageRepository _pageRepository; private readonly IBlogRepository _blogRepository; @@ -46,6 +47,7 @@ namespace Volo.CmsKit private readonly IOptions _tagOptions; private readonly IMediaDescriptorRepository _mediaDescriptorRepository; private readonly IBlobContainer _mediaBlobContainer; + private readonly BlogManager _blogManager; public CmsKitDataSeedContributor( IGuidGenerator guidGenerator, @@ -56,18 +58,20 @@ namespace Volo.CmsKit IRatingRepository ratingRepository, ICurrentTenant currentTenant, IContentRepository contentRepository, - ITagManager tagManager, + TagManager tagManager, + ITagRepository tagRepository, IEntityTagRepository entityTagRepository, IPageRepository pageRepository, IBlogRepository blogRepository, IBlogPostRepository blogPostRepository, BlogPostManager blogPostmanager, IBlogFeatureRepository blogFeatureRepository, - IEntityTagManager entityTagManager, + EntityTagManager entityTagManager, IOptions options, IOptions tagOptions, IMediaDescriptorRepository mediaDescriptorRepository, - IBlobContainer mediaBlobContainer) + IBlobContainer mediaBlobContainer, + BlogManager blogManager) { _guidGenerator = guidGenerator; _cmsUserRepository = cmsUserRepository; @@ -78,6 +82,7 @@ namespace Volo.CmsKit _currentTenant = currentTenant; _contentRepository = contentRepository; _tagManager = tagManager; + _tagRepository = tagRepository; _entityTagManager = entityTagManager; _entityTagRepository = entityTagRepository; _pageRepository = pageRepository; @@ -89,6 +94,7 @@ namespace Volo.CmsKit _tagOptions = tagOptions; _mediaDescriptorRepository = mediaDescriptorRepository; _mediaBlobContainer = mediaBlobContainer; + _blogManager = blogManager; } public async Task SeedAsync(DataSeedContext context) @@ -291,24 +297,40 @@ namespace Volo.CmsKit private async Task SeedTagsAsync() { - var created1 = await _tagManager.InsertAsync(_cmsKitTestData.TagId_1, _cmsKitTestData.EntityType1, _cmsKitTestData.TagName_1); + var created1 = await _tagRepository.InsertAsync( + await _tagManager.CreateAsync( + _cmsKitTestData.TagId_1, + _cmsKitTestData.EntityType1, + _cmsKitTestData.TagName_1)); await _entityTagManager.AddTagToEntityAsync(created1.Id, created1.EntityType, _cmsKitTestData.EntityId1); - var created2 = await _tagManager.InsertAsync(_cmsKitTestData.TagId_2, _cmsKitTestData.EntityType2, _cmsKitTestData.TagName_2); + var created2 = await _tagRepository.InsertAsync( + await _tagManager.CreateAsync( + _cmsKitTestData.TagId_2, + _cmsKitTestData.EntityType2, + _cmsKitTestData.TagName_2)); await _entityTagManager.AddTagToEntityAsync(created2.Id, created2.EntityType, _cmsKitTestData.EntityId2); foreach (var tag in _cmsKitTestData.Content_1_Tags) { - var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_1_EntityType, tag); + var tagEntity = await _tagRepository.InsertAsync( + await _tagManager.CreateAsync( + _guidGenerator.Create(), + _cmsKitTestData.Content_1_EntityType, + tag)); await _entityTagManager.AddTagToEntityAsync(tagEntity.Id, _cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId); } foreach (var tag in _cmsKitTestData.Content_2_Tags) { - var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_2_EntityType, tag); + var tagEntity = await _tagRepository.InsertAsync( + await _tagManager.CreateAsync( + _guidGenerator.Create(), + _cmsKitTestData.Content_2_EntityType, + tag)); await _entityTagManager.AddTagToEntityAsync(tagEntity.Id, _cmsKitTestData.Content_2_EntityType, _cmsKitTestData.Content_2_EntityId); } @@ -331,7 +353,10 @@ namespace Volo.CmsKit private async Task SeedBlogsAsync() { - var blog = await _blogRepository.InsertAsync(new Blog(_cmsKitTestData.Blog_Id, _cmsKitTestData.BlogName, _cmsKitTestData.BlogSlug), autoSave: true); + var blog = await _blogRepository.InsertAsync( + await _blogManager.CreateAsync(_cmsKitTestData.BlogName, _cmsKitTestData.BlogSlug)); + + _cmsKitTestData.Blog_Id = blog.Id; var author = await _cmsUserRepository.GetAsync(_cmsKitTestData.User1Id); diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs index b28a2f0377..7e377a0613 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs @@ -73,7 +73,7 @@ namespace Volo.CmsKit public string TagName_2 => "News"; - public Guid Blog_Id { get; } = Guid.NewGuid(); + public Guid Blog_Id { get; set; } = Guid.NewGuid(); public string BlogName => "Cms Blog"; diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index 1cdfe7ca2e..b6a33ec2ad 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -126,7 +126,7 @@ @if (Model.LanguageSelectListItems.Count > 1) { -
+
diff --git a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSecurityStampValidator.cs b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSecurityStampValidator.cs index cf6e1f8d50..1dcc624a47 100644 --- a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSecurityStampValidator.cs +++ b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSecurityStampValidator.cs @@ -4,29 +4,41 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; namespace Volo.Abp.Identity.AspNetCore { public class AbpSecurityStampValidator : SecurityStampValidator { + protected ITenantConfigurationProvider TenantConfigurationProvider { get; } + protected ICurrentTenant CurrentTenant { get; } + public AbpSecurityStampValidator( IOptions options, SignInManager signInManager, ISystemClock systemClock, - ILoggerFactory loggerFactory) + ILoggerFactory loggerFactory, + ITenantConfigurationProvider tenantConfigurationProvider, + ICurrentTenant currentTenant) : base( - options, + options, signInManager, systemClock, loggerFactory) { + TenantConfigurationProvider = tenantConfigurationProvider; + CurrentTenant = currentTenant; } [UnitOfWork] - public override Task ValidateAsync(CookieValidatePrincipalContext context) + public override async Task ValidateAsync(CookieValidatePrincipalContext context) { - return base.ValidateAsync(context); + var tenant = await TenantConfigurationProvider.GetAsync(saveResolveResult: false); + using (CurrentTenant.Change(tenant?.Id, tenant?.Name)) + { + await base.ValidateAsync(context); + } } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs index 9051dc7d66..851676b840 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs @@ -53,57 +53,54 @@ namespace Volo.Abp.Identity { await IdentityOptions.SetAsync(); - using (IdentityOptions.Value.Password.ClearRequirements()) + var result = new IdentityDataSeedResult(); + //"admin" user + const string adminUserName = "admin"; + var adminUser = await UserRepository.FindByNormalizedUserNameAsync( + LookupNormalizer.NormalizeName(adminUserName) + ); + + if (adminUser != null) { - var result = new IdentityDataSeedResult(); - //"admin" user - const string adminUserName = "admin"; - var adminUser = await UserRepository.FindByNormalizedUserNameAsync( - LookupNormalizer.NormalizeName(adminUserName) - ); + return result; + } - if (adminUser != null) - { - return result; - } + adminUser = new IdentityUser( + GuidGenerator.Create(), + adminUserName, + adminEmail, + tenantId + ) + { + Name = adminUserName + }; + + (await UserManager.CreateAsync(adminUser, adminPassword, validatePassword: false)).CheckErrors(); + result.CreatedAdminUser = true; - adminUser = new IdentityUser( + //"admin" role + const string adminRoleName = "admin"; + var adminRole = + await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName(adminRoleName)); + if (adminRole == null) + { + adminRole = new IdentityRole( GuidGenerator.Create(), - adminUserName, - adminEmail, + adminRoleName, tenantId ) { - Name = adminUserName + IsStatic = true, + IsPublic = true }; - (await UserManager.CreateAsync(adminUser, adminPassword)).CheckErrors(); - result.CreatedAdminUser = true; - - //"admin" role - const string adminRoleName = "admin"; - var adminRole = - await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName(adminRoleName)); - if (adminRole == null) - { - adminRole = new IdentityRole( - GuidGenerator.Create(), - adminRoleName, - tenantId - ) - { - IsStatic = true, - IsPublic = true - }; - - (await RoleManager.CreateAsync(adminRole)).CheckErrors(); - result.CreatedAdminRole = true; - } + (await RoleManager.CreateAsync(adminRole)).CheckErrors(); + result.CreatedAdminRole = true; + } - (await UserManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors(); + (await UserManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors(); - return result; - } + return result; } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs index 69376958b7..508728eea1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs @@ -60,6 +60,17 @@ namespace Volo.Abp.Identity CancellationTokenProvider = cancellationTokenProvider; } + public virtual async Task CreateAsync(IdentityUser user, string password, bool validatePassword) + { + var result = await UpdatePasswordHash(user, password, validatePassword); + if (!result.Succeeded) + { + return result; + } + + return await CreateAsync(user); + } + public virtual async Task GetByIdAsync(Guid id) { var user = await Store.FindByIdAsync(id.ToString(), CancellationToken); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/PasswordOptionsExtensions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/PasswordOptionsExtensions.cs deleted file mode 100644 index 793cc6349e..0000000000 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/PasswordOptionsExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Microsoft.AspNetCore.Identity; - -namespace Volo.Abp.Identity -{ - public static class PasswordOptionsExtensions - { - public static IDisposable ClearRequirements(this PasswordOptions options) - { - var oldRequireDigit = options.RequireDigit; - var oldRequiredLength = options.RequiredLength; - var oldRequireLowercase = options.RequireLowercase; - var oldRequireUppercase = options.RequireUppercase; - var oldRequiredUniqueChars = options.RequiredUniqueChars; - var oldRequireNonAlphanumeric = options.RequireNonAlphanumeric; - - options.RequireDigit = false; - options.RequiredLength = 1; - options.RequireLowercase = false; - options.RequireUppercase = false; - options.RequiredUniqueChars = 1; - options.RequireNonAlphanumeric = false; - - return new DisposeAction(() => - { - options.RequireDigit = oldRequireDigit; - options.RequiredLength = oldRequiredLength; - options.RequireLowercase = oldRequireLowercase; - options.RequireUppercase = oldRequireUppercase; - options.RequiredUniqueChars = oldRequiredUniqueChars; - options.RequireNonAlphanumeric = oldRequireNonAlphanumeric; - }); - } - } -} diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 8fcb74149a..f5b318ce09 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -126,6 +126,7 @@ $projects = ( "framework/src/Volo.Abp.Serialization", "framework/src/Volo.Abp.Settings", "framework/src/Volo.Abp.Sms", + "framework/src/Volo.Abp.Sms.Aliyun", "framework/src/Volo.Abp.Specifications", "framework/src/Volo.Abp.TestBase", "framework/src/Volo.Abp.TextTemplating",