diff --git a/Directory.Packages.props b/Directory.Packages.props index 906b37bd37..a8ec5e695c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -55,7 +55,7 @@ - + diff --git a/modules/docs/Volo.Docs.sln b/modules/docs/Volo.Docs.sln index 6bb8d84d0a..77c5ae1761 100644 --- a/modules/docs/Volo.Docs.sln +++ b/modules/docs/Volo.Docs.sln @@ -63,6 +63,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Docs.MongoDB.Tests", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Installer", "src\Volo.Docs.Installer\Volo.Docs.Installer.csproj", "{50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{AA7E58C3-E223-455F-81BD-4D2E2E152624}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.Application.Contracts", "src\Volo.Docs.Common.Application.Contracts\Volo.Docs.Common.Application.Contracts.csproj", "{D75944C2-FAB0-41A8-AB2A-1A2F97849302}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.Application", "src\Volo.Docs.Common.Application\Volo.Docs.Common.Application.csproj", "{A96F4615-8405-493D-AA06-727D6F29B5F5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -165,6 +171,14 @@ Global {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}.Debug|Any CPU.Build.0 = Debug|Any CPU {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}.Release|Any CPU.ActiveCfg = Release|Any CPU {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}.Release|Any CPU.Build.0 = Release|Any CPU + {D75944C2-FAB0-41A8-AB2A-1A2F97849302}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D75944C2-FAB0-41A8-AB2A-1A2F97849302}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D75944C2-FAB0-41A8-AB2A-1A2F97849302}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D75944C2-FAB0-41A8-AB2A-1A2F97849302}.Release|Any CPU.Build.0 = Release|Any CPU + {A96F4615-8405-493D-AA06-727D6F29B5F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A96F4615-8405-493D-AA06-727D6F29B5F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A96F4615-8405-493D-AA06-727D6F29B5F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A96F4615-8405-493D-AA06-727D6F29B5F5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -197,6 +211,9 @@ Global {DBE846CD-1BED-4F2C-ABF2-94F6240BCB9B} = {A982A58E-1E92-4764-9F56-39E7AABB8556} {C5E2A2A3-D54D-4C2E-97BA-EA50A49ED7AD} = {59D430A9-AC61-4457-8338-5DA0705ABB5D} {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1} = {A982A58E-1E92-4764-9F56-39E7AABB8556} + {AA7E58C3-E223-455F-81BD-4D2E2E152624} = {42416152-5BAB-4706-93A6-57A19E71FE14} + {D75944C2-FAB0-41A8-AB2A-1A2F97849302} = {AA7E58C3-E223-455F-81BD-4D2E2E152624} + {A96F4615-8405-493D-AA06-727D6F29B5F5} = {AA7E58C3-E223-455F-81BD-4D2E2E152624} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {13691265-2547-4FFF-B757-E8FACB05679D} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.csproj b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.csproj new file mode 100644 index 0000000000..acde6b2a6c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.csproj @@ -0,0 +1,33 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + Volo.Docs.Common.Application.Contracts + Volo.Docs.Common.Application.Contracts + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonApplicationContractsModule.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonApplicationContractsModule.cs new file mode 100644 index 0000000000..bc2741fd41 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonApplicationContractsModule.cs @@ -0,0 +1,31 @@ +using Volo.Abp.Application; +using Volo.Abp.Authorization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; +using Volo.Docs.Localization; + +namespace Volo.Docs.Common; + +[DependsOn( + typeof(DocsDomainSharedModule), + typeof(AbpDddApplicationContractsModule), + typeof(AbpAuthorizationAbstractionsModule) +)] +public class DocsCommonApplicationContractsModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts"); + }); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissionDefinitionProvider.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissionDefinitionProvider.cs new file mode 100644 index 0000000000..5f59a60548 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissionDefinitionProvider.cs @@ -0,0 +1,21 @@ +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; +using Volo.Docs.Localization; + +namespace Volo.Docs.Common +{ + public class DocsCommonPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup(DocsCommonPermissions.GroupName, L("Permission:DocumentManagement.Common")); + + group.AddPermission(DocsCommonPermissions.Documents.PdfCreation, L("Permission:PdfCreation")); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissions.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissions.cs new file mode 100644 index 0000000000..c0aae9275a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissions.cs @@ -0,0 +1,19 @@ +using Volo.Abp.Reflection; + +namespace Volo.Docs.Common +{ + public class DocsCommonPermissions + { + public const string GroupName = "Docs.Common"; + + public static class Documents + { + public const string PdfCreation = GroupName + ".PdfCreation"; + } + + public static string[] GetAll() + { + return ReflectionHelper.GetPublicConstantsRecursively(typeof(DocsCommonPermissions)); + } + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonRemoteServiceConsts.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonRemoteServiceConsts.cs new file mode 100644 index 0000000000..6faa6d18fd --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonRemoteServiceConsts.cs @@ -0,0 +1,9 @@ +namespace Volo.Docs.Common +{ + public static class DocsCommonRemoteServiceConsts + { + public const string RemoteServiceName = "AbpDocsCommon"; + + public const string ModuleName = "docs-common"; + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/DocumentPdfGeneratorInput.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/DocumentPdfGeneratorInput.cs new file mode 100644 index 0000000000..989a0e9c40 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/DocumentPdfGeneratorInput.cs @@ -0,0 +1,12 @@ +using System; + +namespace Volo.Docs.Common.Documents; + +public class DocumentPdfGeneratorInput +{ + public Guid ProjectId { get; set; } + + public string Version { get; set; } + + public string LanguageCode { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/IDocumentPdfGeneratorAppService.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/IDocumentPdfGeneratorAppService.cs new file mode 100644 index 0000000000..dc8d87e820 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/IDocumentPdfGeneratorAppService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.Content; + +namespace Volo.Docs.Common.Documents; + +public interface IDocumentPdfGeneratorAppService : IApplicationService +{ + Task GeneratePdfAsync(DocumentPdfGeneratorInput input); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.csproj b/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.csproj new file mode 100644 index 0000000000..d87c22ab09 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.csproj @@ -0,0 +1,23 @@ + + + + + + + net9.0 + Volo.Docs.Common.Application + Volo.Docs.Common.Application + + + + + + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationModule.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationModule.cs new file mode 100644 index 0000000000..16f93808d2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationModule.cs @@ -0,0 +1,25 @@ +using Volo.Abp.Application; +using Volo.Abp.Authorization; +using Volo.Abp.AutoMapper; +using Volo.Abp.Caching; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; +using Volo.Docs.Localization; + +namespace Volo.Docs.Common; + +[DependsOn( + typeof(DocsDomainModule), + typeof(DocsCommonApplicationContractsModule), + typeof(AbpCachingModule), + typeof(AbpAutoMapperModule), + typeof(AbpDddApplicationModule) +)] +public class DocsCommonApplicationModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsDocumentPdfContainer.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsDocumentPdfContainer.cs new file mode 100644 index 0000000000..e8b7f3c3fb --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsDocumentPdfContainer.cs @@ -0,0 +1,9 @@ +using Volo.Abp.BlobStoring; + +namespace Volo.Docs.Common; + +[BlobContainerName("docs-document-pdf")] +public class DocsDocumentPdfContainer +{ + +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGeneratorAppService.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGeneratorAppService.cs new file mode 100644 index 0000000000..860f647a4f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGeneratorAppService.cs @@ -0,0 +1,88 @@ +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Services; +using Volo.Abp.BlobStoring; +using Volo.Abp.Content; +using Volo.Docs.Documents; +using Volo.Docs.Projects; +using Volo.Extensions; + +namespace Volo.Docs.Common.Documents; + +public class DocumentPdfGeneratorAppService : ApplicationService, IDocumentPdfGeneratorAppService +{ + protected IBlobContainer BlobContainer { get; } + protected IProjectRepository ProjectRepository { get; } + protected IDocumentSourceFactory DocumentStoreFactory { get; } + protected IDocumentRepository DocumentRepository { get; } + + public DocumentPdfGeneratorAppService( + IBlobContainer blobContainer, + IProjectRepository projectRepository, + IDocumentSourceFactory documentStoreFactory, + IDocumentRepository documentRepository) + { + BlobContainer = blobContainer; + ProjectRepository = projectRepository; + DocumentStoreFactory = documentStoreFactory; + DocumentRepository = documentRepository; + } + + public virtual async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + { + var project = await ProjectRepository.GetAsync(input.ProjectId); + var fileName = CalculateDocumentPdfFileName(project.Name, input.Version, input.LanguageCode); + var stream = await BlobContainer.GetOrNullAsync(fileName); + + if(stream != null) + { + return new RemoteStreamContent(stream, fileName , "application/pdf"); + } + + var documentStore = DocumentStoreFactory.Create(project.DocumentStoreType); + var navigation = await GetNavigationAsync(documentStore, project, input.LanguageCode, input.Version); + + + } + + protected virtual string CalculateDocumentPdfFileName(string projectName, string version, string languageCode) + { + return $"{projectName.ToLower()}-{version.ToLower()}--{languageCode.ToLower()}"; + } + + private async Task GetNavigationAsync( + IDocumentSource documentStore, + Project project, + string languageCode, + string version) + { + var navigationDocument = await GetDocumentAsync(documentStore, project, project.NavigationDocumentName, languageCode, version); + + if (!DocsJsonSerializerHelper.TryDeserialize(navigationDocument.Content, out var navigation)) + { + throw new UserFriendlyException($"Cannot validate navigation file '{project.NavigationDocumentName}' for the project {project.Name}."); + } + + return navigation; + } + + private async Task GetDocumentAsync( + IDocumentSource documentStore, + Project project, + string documentName, + string languageCode, + string version) + { + version = string.IsNullOrWhiteSpace(version) ? project.LatestVersionBranchName : version; + var document = await DocumentRepository.FindAsync(project.Id, documentName, version, languageCode); + + if (document != null) + { + return document; + } + + document = await documentStore.GetDocumentAsync(project, documentName, languageCode, version); + + return document; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs index 015f711850..9b270297a7 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs @@ -24,6 +24,9 @@ namespace Volo.Docs.Documents [JsonPropertyName("keywords")] public string[] Keywords { get; set; } + + [JsonPropertyName("ignoreOnDownload")] + public bool IgnoreOnDownload { get; set; } public bool IsLeaf => !HasChildItems;