From b538b30ab3232852513585099cd2f9c8a21e4e94 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 4 Mar 2025 17:53:57 +0800 Subject: [PATCH 01/19] Add docs module common projects --- Directory.Packages.props | 2 +- modules/docs/Volo.Docs.sln | 17 ++++ ...o.Docs.Common.Application.Contracts.csproj | 33 +++++++ .../DocsCommonApplicationContractsModule.cs | 31 +++++++ .../DocsCommonPermissionDefinitionProvider.cs | 21 +++++ .../Volo/Docs/Common/DocsCommonPermissions.cs | 19 ++++ .../Common/DocsCommonRemoteServiceConsts.cs | 9 ++ .../Documents/DocumentPdfGeneratorInput.cs | 12 +++ .../IDocumentPdfGeneratorAppService.cs | 10 +++ .../Volo.Docs.Common.Application.csproj | 23 +++++ .../Common/DocsCommonApplicationModule.cs | 25 ++++++ .../Docs/Common/DocsDocumentPdfContainer.cs | 9 ++ .../DocumentPdfGeneratorAppService.cs | 88 +++++++++++++++++++ .../Volo/Docs/Documents/NavigationNode.cs | 3 + 14 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.csproj create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonApplicationContractsModule.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissionDefinitionProvider.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissions.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonRemoteServiceConsts.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/DocumentPdfGeneratorInput.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/IDocumentPdfGeneratorAppService.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.csproj create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationModule.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsDocumentPdfContainer.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGeneratorAppService.cs 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; From 14c842363cb08e7b1de3779e830fd34faf3df721 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 24 Mar 2025 18:08:48 +0800 Subject: [PATCH 02/19] Add DocumentPdfGeneratorAppService to generate PDF --- Directory.Packages.props | 5 +- modules/docs/Volo.Docs.sln | 42 +- .../app/VoloDocs.Web/VoloDocsWebModule.cs | 6 + ...lo.Docs.Admin.Application.Contracts.csproj | 1 + .../DocsAdminApplicationContractsModule.cs | 4 +- .../Volo.Docs.Admin.Application.csproj | 1 + .../Docs/Admin/DocsAdminApplicationModule.cs | 2 + .../Volo.Docs.Admin.HttpApi.csproj | 1 + .../Volo/Docs/Admin/DocsAdminHttpApiModule.cs | 4 +- .../DocsCommonPermissionDefinitionProvider.cs | 2 +- .../Volo/Docs/Common/DocsCommonPermissions.cs | 2 +- .../Volo.Docs.Common.Application.csproj | 3 + .../DocsDocumentPdfContainer.cs | 2 +- .../DocsDocumentPdfGeneratorOptions.cs | 64 +++ .../Common/Documents/DocumentPdfGenerator.cs | 419 ++++++++++++++++++ .../DocumentPdfGeneratorAppService.cs | 84 +--- .../Documents/HtmlIdTagWorkerFactory.cs | 41 ++ .../Common/Documents/IDocumentPdfGenerator.cs | 11 + .../Volo.Docs.Common.HttpApi.Client.csproj | 19 + .../Volo.Docs.Common.HttpApi.csproj | 18 + .../Volo/Docs/DocsCommonHttpApiModule.cs | 35 ++ .../Volo/Docs/DocsControllerBase.cs | 12 + .../DocsDocumentPdfGeneratorController.cs | 30 ++ .../Volo.Docs.Domain.Shared.csproj | 1 + .../Volo/Docs/Documents/DocumentParams.cs | 23 + .../DocumentPartialTemplateContent.cs | 2 +- .../DocumentPartialTemplateWithValues.cs | 10 + .../Rendering/DocumentRenderParameters.cs | 20 + .../Rendering/IDocumentSectionRenderer.cs | 12 + .../ScribanDocumentSectionRenderer.cs | 302 +++++++++++++ .../Volo.Docs.Web/DocsWebAutoMapperProfile.cs | 3 - .../DocumentPartialTemplateWithValuesDto.cs | 11 - .../DocumentRenderParameters.cs | 8 - .../IDocumentSectionRenderer.cs | 17 - .../IWebDocumentSectionRenderer.cs | 14 + .../ScribanDocumentSectionRenderer.cs | 316 ------------- .../ScribanWebDocumentSectionRenderer.cs | 38 ++ .../Pages/Documents/Project/Index.cshtml.cs | 43 +- .../src/Volo.Docs.Web/Volo.Docs.Web.csproj | 2 +- 39 files changed, 1171 insertions(+), 459 deletions(-) rename modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/{ => Documents}/DocsDocumentPdfContainer.cs (74%) create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfGeneratorOptions.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGenerator.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/HtmlIdTagWorkerFactory.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/IDocumentPdfGenerator.cs create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.csproj create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.csproj create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsCommonHttpApiModule.cs create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsControllerBase.cs create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs rename modules/docs/src/{Volo.Docs.Web/HtmlConverting => Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering}/DocumentPartialTemplateContent.cs (77%) create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateWithValues.cs create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentRenderParameters.cs create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/IDocumentSectionRenderer.cs create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs delete mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs delete mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs delete mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs create mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs delete mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs create mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index a8ec5e695c..59aa37e3fe 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -38,6 +38,9 @@ + + + @@ -183,4 +186,4 @@ - + \ No newline at end of file diff --git a/modules/docs/Volo.Docs.sln b/modules/docs/Volo.Docs.sln index 77c5ae1761..af9282dca3 100644 --- a/modules/docs/Volo.Docs.sln +++ b/modules/docs/Volo.Docs.sln @@ -63,11 +63,15 @@ 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}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.Application", "src\Volo.Docs.Common.Application\Volo.Docs.Common.Application.csproj", "{914EDEC4-EFCE-46D5-B6E0-A928B1907307}" 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}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.Application.Contracts", "src\Volo.Docs.Common.Application.Contracts\Volo.Docs.Common.Application.Contracts.csproj", "{8CA19527-6870-4617-B6D1-EA8CAF224DF4}" 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}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.HttpApi", "src\Volo.Docs.Common.HttpApi\Volo.Docs.Common.HttpApi.csproj", "{052C076D-56FF-4DFA-838B-48BD30A1DB0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.HttpApi.Client", "src\Volo.Docs.Common.HttpApi.Client\Volo.Docs.Common.HttpApi.Client.csproj", "{349C36A0-552D-44A3-AC74-03A4828D43AB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -171,14 +175,22 @@ 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 + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Debug|Any CPU.Build.0 = Debug|Any CPU + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Release|Any CPU.ActiveCfg = Release|Any CPU + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Release|Any CPU.Build.0 = Release|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Release|Any CPU.Build.0 = Release|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Release|Any CPU.Build.0 = Release|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -211,9 +223,11 @@ 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} + {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} = {42416152-5BAB-4706-93A6-57A19E71FE14} + {914EDEC4-EFCE-46D5-B6E0-A928B1907307} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} + {8CA19527-6870-4617-B6D1-EA8CAF224DF4} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} + {052C076D-56FF-4DFA-838B-48BD30A1DB0A} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} + {349C36A0-552D-44A3-AC74-03A4828D43AB} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {13691265-2547-4FFF-B757-E8FACB05679D} diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index 743944c6d3..cf864f1e50 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -36,6 +36,7 @@ using Volo.Abp.PermissionManagement.HttpApi; using Volo.Abp.Validation.Localization; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Abp.Caching.StackExchangeRedis; +using Volo.Docs.Common.Documents; namespace VoloDocs.Web { @@ -170,6 +171,11 @@ namespace VoloDocs.Web options.EnableGoogleProgrammableSearchEngine = true; options.GoogleSearchEngineId = "77c7266532da1427f"; }); + + Configure(options => + { + options.BaseUrl = configuration["App:selfUrl"]; + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj index a49d9146db..796a4a83c4 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj @@ -18,6 +18,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs index 0962a28aef..1e20041974 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs @@ -4,6 +4,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; +using Volo.Docs.Common; using Volo.Docs.Localization; namespace Volo.Docs.Admin @@ -11,7 +12,8 @@ namespace Volo.Docs.Admin [DependsOn( typeof(DocsDomainSharedModule), typeof(AbpDddApplicationContractsModule), - typeof(AbpAuthorizationAbstractionsModule) + typeof(AbpAuthorizationAbstractionsModule), + typeof(DocsCommonApplicationContractsModule) )] public class DocsAdminApplicationContractsModule : AbpModule { diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj b/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj index 3d947ead5e..7279eeee67 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj @@ -12,6 +12,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs index 0b78c53973..7e6983d65e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs @@ -3,12 +3,14 @@ using Volo.Abp.Application; using Volo.Abp.AutoMapper; using Volo.Abp.Caching; using Volo.Abp.Modularity; +using Volo.Docs.Common; namespace Volo.Docs.Admin { [DependsOn( typeof(DocsDomainModule), typeof(DocsAdminApplicationContractsModule), + typeof(DocsCommonApplicationModule), typeof(AbpCachingModule), typeof(AbpAutoMapperModule), typeof(AbpDddApplicationModule) diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj index 6d718f03bb..25a0be0294 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj @@ -12,6 +12,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs index ed62f35e6f..ba7f1f7fbb 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs @@ -4,12 +4,14 @@ using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Docs.Localization; using Microsoft.Extensions.DependencyInjection; +using Volo.Docs.Common; namespace Volo.Docs.Admin { [DependsOn( typeof(DocsAdminApplicationContractsModule), - typeof(AbpAspNetCoreMvcModule) + typeof(AbpAspNetCoreMvcModule), + typeof(DocsCommonHttpApiModule) )] public class DocsAdminHttpApiModule : AbpModule { 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 index 5f59a60548..16f3597152 100644 --- 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 @@ -10,7 +10,7 @@ namespace Volo.Docs.Common { var group = context.AddGroup(DocsCommonPermissions.GroupName, L("Permission:DocumentManagement.Common")); - group.AddPermission(DocsCommonPermissions.Documents.PdfCreation, L("Permission:PdfCreation")); + group.AddPermission(DocsCommonPermissions.Documents.PdfGeneration, L("Permission:PdfGeneration")); } private static LocalizableString L(string 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 index c0aae9275a..4d2d2a3827 100644 --- 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 @@ -8,7 +8,7 @@ namespace Volo.Docs.Common public static class Documents { - public const string PdfCreation = GroupName + ".PdfCreation"; + public const string PdfGeneration = GroupName + ".PdfGeneration"; } public static string[] GetAll() 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 index d87c22ab09..fa4173f985 100644 --- 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 @@ -17,6 +17,9 @@ + + + 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/Documents/DocsDocumentPdfContainer.cs similarity index 74% rename from modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsDocumentPdfContainer.cs rename to modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfContainer.cs index e8b7f3c3fb..63e3652a3b 100644 --- a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsDocumentPdfContainer.cs +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfContainer.cs @@ -1,6 +1,6 @@ using Volo.Abp.BlobStoring; -namespace Volo.Docs.Common; +namespace Volo.Docs.Common.Documents; [BlobContainerName("docs-document-pdf")] public class DocsDocumentPdfContainer diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfGeneratorOptions.cs new file mode 100644 index 0000000000..6d2ff2bc82 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfGeneratorOptions.cs @@ -0,0 +1,64 @@ +namespace Volo.Docs.Common.Documents; + +public class DocsDocumentPdfGeneratorOptions +{ + public string HtmlLayout { get; set; } + public string HtmlStyles { get; set; } + + public string BaseUrl { get; set; } + + public DocsDocumentPdfGeneratorOptions() + { + HtmlLayout = @" + + + + + + + {{content-placeholder}} + + "; + + HtmlStyles = @" + body { margin: 20px; line-height: 1.6; font-family: Arial, sans-serif;} + a { text-decoration: none; } + .page { + page-break-after: always; + margin-bottom: 30px; + padding: 15px; + } + img { + max-width:100%; + height: auto; + display: block; + } + code, pre { + background: #f8fafc; + white-space: pre-wrap; + word-wrap: break-word; + } + pre code { padding: 0; border: none; } + code { + padding: 2px 6px; + border-radius: 4px; + border: 1px solid #e2e8f0; + font-family: Consolas, monospace; + } + pre { + position: relative; + padding: 16px; + padding-top: calc(16px * 2.5); + border-radius: 8px; + border: 1px solid #e2e8f0; + } + blockquote { + border-left: 4px solid #e2e8f0; + margin: 20px 0; + padding: 10px 20px; + background: #f8fafc; + }"; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGenerator.cs new file mode 100644 index 0000000000..f54eafe116 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGenerator.cs @@ -0,0 +1,419 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; +using iText.Html2pdf; +using iText.Kernel.Pdf; +using iText.Kernel.Pdf.Action; +using Markdig; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Volo.Abp; +using Volo.Abp.Content; +using Volo.Docs.Documents; +using Volo.Docs.Documents.Rendering; +using Volo.Docs.Projects; +using Volo.Extensions; +using ITextDocument = iText.Layout.Document; + +namespace Volo.Docs.Common.Documents; + +public class DocumentPdfGenerator : IDocumentPdfGenerator +{ + protected IDocumentSourceFactory DocumentStoreFactory { get; } + protected IDocumentRepository DocumentRepository { get; } + protected IDocumentSectionRenderer DocumentSectionRenderer { get; } + protected IOptions Options { get; } + protected ILogger Logger { get; set; } + protected IDocumentSource DocumentSource { get; set; } + protected DocumentParams DocumentParams { get; set; } + protected List AllPdfDocumentNodes { get; set; } = new(); + protected MarkdownPipeline MarkdownPipeline { get; } = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build(); + + public DocumentPdfGenerator( + IDocumentSourceFactory documentStoreFactory, + IDocumentRepository documentRepository, + IOptions options, + IDocumentSectionRenderer documentSectionRenderer) + { + DocumentStoreFactory = documentStoreFactory; + DocumentRepository = documentRepository; + Options = options; + DocumentSectionRenderer = documentSectionRenderer; + Logger = NullLogger.Instance; + } + + public virtual async Task GenerateAsync(Project project, string version, string languageCode) + { + DocumentSource = DocumentStoreFactory.Create(project.DocumentStoreType); + DocumentParams = await GetDocumentParamsAsync(project, version, languageCode); + var navigation = await GetNavigationAsync(project, version, languageCode); + + await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode); + var htmlContent = await ConvertDocumentsToHtmlAsync(AllPdfDocumentNodes); + + var pdfStream = await GeneratePdfAsync(htmlContent); + + return new RemoteStreamContent(pdfStream, CalculateDocumentPdfFileName(project.ShortName, version, languageCode), "application/pdf"); + } + + protected virtual async Task ConvertDocumentsToHtmlAsync(List pdfDocumentNodes) + { + var contentBuilder = new StringBuilder(); + + foreach (var pdfDocumentNode in pdfDocumentNodes) + { + if (pdfDocumentNode.Document != null) + { + var renderedDocument = await RenderDocumentAsync(pdfDocumentNode); + renderedDocument = NormalizeHtmlContent(pdfDocumentNode, Markdown.ToHtml(renderedDocument, MarkdownPipeline)); + contentBuilder.AppendLine(renderedDocument); + } + + if (pdfDocumentNode.HasChildren) + { + contentBuilder.AppendLine(await ConvertDocumentsToHtmlAsync(pdfDocumentNode.Children)); + } + } + + return contentBuilder.ToString(); + } + + protected virtual Task GeneratePdfAsync(string htmlContent) + { + var pdfStream = new MemoryStream(); + var pdfWrite = new PdfWriter(pdfStream); + var pdfDocument = new PdfDocument(pdfWrite); + var textDocument = new ITextDocument(pdfDocument); + pdfWrite.SetCloseStream(false); + + var htmlBuilder = new StringBuilder(); + htmlBuilder.Append(Options.Value.HtmlLayout); + htmlBuilder.Replace("{{style-placeholder}}", Options.Value.HtmlStyles); + htmlBuilder.Replace("{{content-placeholder}}", htmlContent); + + var converter = new ConverterProperties(); + var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); + converter.SetTagWorkerFactory(tagWorkerFactory); + + HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter); + + tagWorkerFactory.AddNamedDestinations(); + var pdfOutlines = pdfDocument.GetOutlines(false); + BuildPdfOutlines(pdfOutlines, AllPdfDocumentNodes); + + textDocument.Close(); + pdfStream.Position = 0; + return Task.FromResult(pdfStream); + } + + private void BuildPdfOutlines(PdfOutline parentOutline, List pdfDocumentNodes) + { + foreach (var pdfDocumentNode in pdfDocumentNodes) + { + if (pdfDocumentNode.IgnoreOnOutline) + { + continue; + } + + var outline = parentOutline.AddOutline(pdfDocumentNode.Title); + if (!pdfDocumentNode.Id.IsNullOrWhiteSpace()) + { + outline.AddAction(PdfAction.CreateGoTo(pdfDocumentNode.Id)); + } + + if (pdfDocumentNode.HasChildren) + { + BuildPdfOutlines(outline, pdfDocumentNode.Children); + } + } + } + + protected virtual async Task RenderDocumentAsync(PdfDocumentNode pdfDocumentNode) + { + var renderedDocument = await DocumentSectionRenderer.RenderAsync(pdfDocumentNode.Document.Content, pdfDocumentNode.RenderParameters); + if (pdfDocumentNode.RenderParameters != null) + { + renderedDocument = SetDocumentTitle(renderedDocument, pdfDocumentNode.Title); + } + + return renderedDocument; + } + + protected virtual async Task SetAllPdfDocumentNodesAsync( + List navigations, + Project project, + string version, + string languageCode, + PdfDocumentNode parentPdfDocumentNode = null) + { + var parameterCombinationsDocuments = new List(); + foreach (var navigation in navigations) + { + if (navigation.IgnoreOnDownload) + { + continue; + } + try + { + var pdfDocumentNode = new PdfDocumentNode + { + Title = navigation.Text, + IgnoreOnOutline = navigation.Path == "index.md" + }; + + if (!navigation.Path.IsNullOrWhiteSpace()) + { + var path = NormalizeNavigationPath(navigation.Path); + var document = await GetDocumentAsync(project, path, version, languageCode); + var parameters = await DocumentSectionRenderer.GetAvailableParametersAsync(document.Content); + var parameterCombinations = GenerateAllParameterCombinations(parameters.Keys.ToList(), parameters); + var firstParameterCombination = parameterCombinations.FirstOrDefault(); + + pdfDocumentNode.Document = document; + pdfDocumentNode.Title = GetDocumentTitle(navigation.Text, document.Content, firstParameterCombination); + pdfDocumentNode.Id = GetDocumentId(navigation.Path, firstParameterCombination); + pdfDocumentNode.RenderParameters = firstParameterCombination; + + if(parameters.Count <= 1) + { + if (parentPdfDocumentNode == null) + { + AllPdfDocumentNodes.AddRange(parameterCombinationsDocuments); + } + else + { + parentPdfDocumentNode.Children.AddRange(parameterCombinationsDocuments); + } + } + else + { + for (var i = 1; i < parameterCombinations.Count; i++) + { + var parameterCombination = parameterCombinations[i]; + parameterCombinationsDocuments.Add(new PdfDocumentNode + { + Document = document, + Title = GetDocumentTitle(navigation.Text, document.Content, parameterCombination), + Id = GetDocumentId(navigation.Path, parameterCombination), + RenderParameters = parameterCombination + }); + } + } + } + + if (parentPdfDocumentNode == null) + { + AllPdfDocumentNodes.Add(pdfDocumentNode); + } + else + { + parentPdfDocumentNode.Children.Add(pdfDocumentNode); + } + + if (navigation.HasChildItems) + { + await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode, pdfDocumentNode); + } + } + catch (Exception e) + { + Logger.LogWarning(e, $"Cannot get document for the path '{navigation.Path}' in the project {project.Name}."); + } + } + } + + protected virtual string CalculateDocumentPdfFileName(string projectName, string version, string languageCode) + { + return $"{projectName.ToLower()}-{languageCode.ToLower()}.pdf"; + } + + private string NormalizeNavigationPath(string path) + { + return !path.EndsWith(".md") ? Path.Combine(path, "index.md") : path; + } + + private async Task GetNavigationAsync( + Project project, + string version, + string languageCode) + { + var navigationDocument = await GetDocumentAsync(project, project.NavigationDocumentName, version, languageCode); + + if (!DocsJsonSerializerHelper.TryDeserialize(navigationDocument.Content, out var navigation)) + { + throw new UserFriendlyException($"Cannot validate navigation file '{project.NavigationDocumentName}' for the project {project.Name}."); + } + + navigation.Items.Insert(0, new NavigationNode + { + Text = "Index", + Path = "index.md" + }); + + return navigation; + } + + private async Task GetDocumentParamsAsync( + Project project, + string version, + string languageCode) + { + if (project.ParametersDocumentName.IsNullOrWhiteSpace()) + { + return new DocumentParams(); + } + + try + { + var documentParamsDocument = await GetDocumentAsync(project, project.ParametersDocumentName, version, languageCode); + + if (!DocsJsonSerializerHelper.TryDeserialize(documentParamsDocument.Content, out var documentParams)) + { + throw new UserFriendlyException($"Cannot validate document params file '{project.ParametersDocumentName}' for the project {project.Name}."); + } + + return documentParams; + } + catch (Exception e) + { + Logger.LogError(e, $"Cannot get document params for the project {project.Name}.", e); + return new DocumentParams(); + } + } + + private async Task GetDocumentAsync( + Project project, + string documentName, + string version, + string languageCode) + { + version = string.IsNullOrWhiteSpace(version) ? project.LatestVersionBranchName : version; + var document = await DocumentRepository.FindAsync(project.Id, documentName, version, languageCode); + + if (document != null) + { + return document; + } + + document = await DocumentSource.GetDocumentAsync(project, documentName, languageCode, version); + + return document; + } + + protected virtual List GenerateAllParameterCombinations(List parameterKeys, Dictionary> parameters) + { + var parameterCombinations = new List(); + + if (parameters.Count <= 0) + { + return parameterCombinations; + } + + GenerateCombinations(0, new DocumentRenderParameters()); + return parameterCombinations; + + void GenerateCombinations(int keyIndex, DocumentRenderParameters currentCombination) + { + if (keyIndex == parameterKeys.Count) + { + parameterCombinations.Add(new DocumentRenderParameters(currentCombination)); + return; + } + + var currentKey = parameterKeys[keyIndex]; + foreach (var value in parameters[currentKey]) + { + currentCombination[currentKey] = value; + GenerateCombinations(keyIndex + 1, currentCombination); + } + } + } + + private string SetDocumentTitle(string content, string title) + { + var titleLine = content.Split('\n').FirstOrDefault(x => x.TrimStart().StartsWith("#")); + if (titleLine == null) + { + return content; + } + + var newTitle = $"# {title}"; + return content.Replace(titleLine, newTitle); + } + + private string GetDocumentTitle(string title, string content, DocumentRenderParameters parameters) + { + if (parameters == null || parameters.Count <= 0) + { + return title; + } + + var titleLine = content.Split('\n').FirstOrDefault(x => x.TrimStart().StartsWith("#")); + if (titleLine == null) + { + return title; + } + + var paramValues = parameters.Select(x => $"{DocumentParams.Parameters.FirstOrDefault(p => p.Name == x.Key)?.DisplayName ?? x.Key}: {x.Value}").ToList(); + return titleLine.TrimStart('#').Trim() + $" ({string.Join(", ", paramValues)})"; + } + + + private string GetDocumentId(string path, DocumentRenderParameters parameters) + { + var id = path.Replace(".md",string.Empty).Replace("/","-").Replace(" ", "-").ToLower(); + if (parameters != null) + { + id = $"{id}{parameters.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-")}"; + } + return id; + } + + private string NormalizeHtmlContent(PdfDocumentNode pdfDocumentNode, string htmlContent) + { + htmlContent = $"
{htmlContent}
"; + + htmlContent = Regex.Replace(htmlContent, @"(]*)src=""([^""]*)""([^>]*>)", delegate (Match match) + { + if (IsExternalLink(match.Groups[2].Value)) + { + return match.Value; + } + + var rootUrl = IsExternalLink(pdfDocumentNode.Document.RawRootUrl) + ? pdfDocumentNode.Document.RawRootUrl.EnsureEndsWith('/') + : Options.Value.BaseUrl.EnsureEndsWith('/') + pdfDocumentNode.Document.RawRootUrl.TrimStart('/').EnsureEndsWith('/'); + var newImageSource = rootUrl + + (pdfDocumentNode.Document.LocalDirectory.IsNullOrEmpty() ? "" : pdfDocumentNode.Document.LocalDirectory.TrimStart('/').EnsureEndsWith('/')) + + match.Groups[2].Value.TrimStart('/'); + + return match.Groups[1] + " src=\"" + HttpUtility.HtmlEncode(newImageSource) + "\" " + match.Groups[3]; + + }, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline); + + return htmlContent; + } + + private bool IsExternalLink(string link) + { + return link.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || + link.StartsWith("https://", StringComparison.OrdinalIgnoreCase); + } + + protected class PdfDocumentNode + { + public Document Document { get; set; } + public string Title { get; set; } + public string Id { get; set; } + public List Children { get; set; } = []; + public DocumentRenderParameters RenderParameters { get; set; } + public bool HasChildren => Children.Any(); + public bool IgnoreOnOutline { get; set; } + } +} \ 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 index 860f647a4f..cc752d1492 100644 --- 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 @@ -1,88 +1,28 @@ using System.Threading.Tasks; -using Volo.Abp; +using Microsoft.AspNetCore.Authorization; 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; +[Authorize(DocsCommonPermissions.Documents.PdfGeneration)] public class DocumentPdfGeneratorAppService : ApplicationService, IDocumentPdfGeneratorAppService { - protected IBlobContainer BlobContainer { get; } - protected IProjectRepository ProjectRepository { get; } - protected IDocumentSourceFactory DocumentStoreFactory { get; } - protected IDocumentRepository DocumentRepository { get; } - + private readonly IDocumentPdfGenerator _documentPdfGenerator; + private readonly IProjectRepository _projectRepository; + public DocumentPdfGeneratorAppService( - IBlobContainer blobContainer, - IProjectRepository projectRepository, - IDocumentSourceFactory documentStoreFactory, - IDocumentRepository documentRepository) + IDocumentPdfGenerator documentPdfGenerator, + IProjectRepository projectRepository) { - BlobContainer = blobContainer; - ProjectRepository = projectRepository; - DocumentStoreFactory = documentStoreFactory; - DocumentRepository = documentRepository; + _documentPdfGenerator = documentPdfGenerator; + _projectRepository = projectRepository; } - - 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) + public async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) { - 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; + var project = await _projectRepository.GetAsync(input.ProjectId); + return await _documentPdfGenerator.GenerateAsync(project, input.Version, input.LanguageCode); } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/HtmlIdTagWorkerFactory.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/HtmlIdTagWorkerFactory.cs new file mode 100644 index 0000000000..02078486e2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/HtmlIdTagWorkerFactory.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using iText.Html2pdf.Attach; +using iText.Html2pdf.Attach.Impl; +using iText.Kernel.Pdf; +using iText.Kernel.Pdf.Navigation; +using iText.StyledXmlParser.Node; + +namespace Volo.Docs.Common.Documents; + +public class HtmlIdTagWorkerFactory: DefaultTagWorkerFactory +{ + private readonly PdfDocument _pdfDocument; + private readonly Dictionary _pageDestinations = new(); + + public HtmlIdTagWorkerFactory(PdfDocument pdfDocument) + { + _pdfDocument = pdfDocument; + } + + public override ITagWorker GetCustomTagWorker(IElementNode tag, ProcessorContext context) + { + var tagClass = tag.GetAttribute("class"); + if (tag.Name().Equals("div") && tagClass =="page") + { + var id = tag.GetAttribute("id"); + _pageDestinations[id] = _pdfDocument.GetNumberOfPages() + 1; + } + + return base.GetCustomTagWorker(tag, context); + } + + public void AddNamedDestinations() + { + foreach (var pageDestination in _pageDestinations) + { + var page = _pdfDocument.GetPage(pageDestination.Value); + var destination = PdfExplicitDestination.CreateFit(page); + _pdfDocument.AddNamedDestination(pageDestination.Key, destination.GetPdfObject()); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/IDocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/IDocumentPdfGenerator.cs new file mode 100644 index 0000000000..3fced15bf8 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/IDocumentPdfGenerator.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Volo.Abp.Content; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Projects; + +namespace Volo.Docs.Common.Documents; + +public interface IDocumentPdfGenerator : ITransientDependency +{ + Task GenerateAsync(Project project, string version, string languageCode); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.csproj b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.csproj new file mode 100644 index 0000000000..ff4c3301fc --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.csproj @@ -0,0 +1,19 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + Volo.Docs.Common.HttpApi.Client + Volo.Docs.Common.HttpApi.Client + + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.csproj b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.csproj new file mode 100644 index 0000000000..001778b838 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.csproj @@ -0,0 +1,18 @@ + + + + + + + net9.0 + Volo.Docs.Common.HttpApi + Volo.Docs.Common.HttpApi + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsCommonHttpApiModule.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsCommonHttpApiModule.cs new file mode 100644 index 0000000000..09ff45507b --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsCommonHttpApiModule.cs @@ -0,0 +1,35 @@ +using Localization.Resources.AbpUi; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Docs.Common; +using Volo.Docs.Localization; + +namespace Volo.Docs +{ + [DependsOn( + typeof(DocsCommonApplicationContractsModule), + typeof(AbpAspNetCoreMvcModule) + )] + public class DocsCommonHttpApiModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(DocsCommonHttpApiModule).Assembly); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Resources + .Get() + .AddBaseTypes(typeof(AbpUiResource)); + }); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsControllerBase.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsControllerBase.cs new file mode 100644 index 0000000000..8d730acd4f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsControllerBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.AspNetCore.Mvc; +using Volo.Docs.Localization; + +namespace Volo.Docs; + +public abstract class DocsControllerBase : AbpControllerBase +{ + protected DocsControllerBase() + { + LocalizationResource = typeof(DocsResource); + } +} diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs new file mode 100644 index 0000000000..bfd5be9224 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Asp.Versioning; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp; +using Volo.Abp.Content; +using Volo.Docs.Common; +using Volo.Docs.Common.Documents; + +namespace Volo.Docs.Documents; + +[RemoteService(Name = DocsCommonRemoteServiceConsts.RemoteServiceName)] +[Area(DocsCommonRemoteServiceConsts.ModuleName)] +[ControllerName("Document")] +[Route("api/docs/documents")] +public class DocsDocumentPdfGeneratorController : DocsControllerBase, IDocumentPdfGeneratorAppService +{ + protected IDocumentPdfGeneratorAppService DocumentPdfGeneratorAppService { get; } + + public DocsDocumentPdfGeneratorController(IDocumentPdfGeneratorAppService documentPdfGeneratorAppService) + { + DocumentPdfGeneratorAppService = documentPdfGeneratorAppService; + } + + [HttpGet] + [Route("pdf")] + public Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + { + return DocumentPdfGeneratorAppService.GeneratePdfAsync(input); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj b/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj index 8a4911b9b9..2ce827d009 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj @@ -11,6 +11,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs new file mode 100644 index 0000000000..ae116b850f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Volo.Docs.Documents; + +public class DocumentParams +{ + [JsonPropertyName("Parameters")] + public List Parameters { get; set; } = new(); + + + public class DocumentParameter + { + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } + + [JsonPropertyName("values")] + public List> Values { get; set; } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateContent.cs similarity index 77% rename from modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs rename to modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateContent.cs index 5db9fc8164..66a5d27a16 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateContent.cs @@ -1,4 +1,4 @@ -namespace Volo.Docs.HtmlConverting +namespace Volo.Docs.Documents.Rendering { public class DocumentPartialTemplateContent { diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateWithValues.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateWithValues.cs new file mode 100644 index 0000000000..4ae900256e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateWithValues.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Volo.Docs.Documents.Rendering; + +public class DocumentPartialTemplateWithValues +{ + public string Path { get; set; } + + public Dictionary Parameters { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentRenderParameters.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentRenderParameters.cs new file mode 100644 index 0000000000..dc7bf95e62 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentRenderParameters.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace Volo.Docs.Documents.Rendering +{ + public class DocumentRenderParameters : Dictionary + { + public DocumentRenderParameters() + { + + } + + public DocumentRenderParameters(DocumentRenderParameters renderParameters) + { + foreach (var parameter in renderParameters) + { + Add(parameter.Key, parameter.Value); + } + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/IDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/IDocumentSectionRenderer.cs new file mode 100644 index 0000000000..9179601545 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/IDocumentSectionRenderer.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Docs.Documents.Rendering; + +public interface IDocumentSectionRenderer : ITransientDependency +{ + Task RenderAsync(string document, DocumentRenderParameters parameters = null, List partialTemplates = null); + + Task>> GetAvailableParametersAsync(string document); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs new file mode 100644 index 0000000000..02881c5a67 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Scriban; +using Volo.Abp; +using Volo.Extensions; + +namespace Volo.Docs.Documents.Rendering; + +public class ScribanDocumentSectionRenderer : IDocumentSectionRenderer +{ + protected readonly static List DocsJsonSections = + [ + new("````json", "````"), + new("```json", "```") + ]; + + protected const string DocsParam = "//[doc-params]"; + protected const string DocsTemplates = "//[doc-template]"; + protected const string DocsNav = "//[doc-nav]"; + + public ILogger Logger { get; set; } + + public ScribanDocumentSectionRenderer() + { + Logger = NullLogger.Instance; + } + + public async Task RenderAsync( + string document, + DocumentRenderParameters parameters = null, + List partialTemplates = null) + { + if (partialTemplates != null && partialTemplates.Any()) + { + document = SetPartialTemplates(document, partialTemplates); + } + + var scribanTemplate = Template.Parse(document); + + if (parameters == null) + { + return await scribanTemplate.RenderAsync(); + } + + var result = await scribanTemplate.RenderAsync(parameters); + + return RemoveOptionsJson(result, DocsParam, DocsNav); + } + + public Task>> GetAvailableParametersAsync(string document) + { + return GetSectionAsync>>(document, DocsParam); + } + + protected virtual async Task GetSectionAsync(string document, string sectionName) where T : new() + { + try + { + if (!HasJsonSection(document) || !document.Contains(sectionName)) + { + return new T(); + } + + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, _) = + GetJsonBeginEndIndexesAndPureJson(document, sectionName); + + if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) + { + return new T(); + } + + var pureJson = insideJsonSection.Replace(sectionName, "").Trim(); + + if (!DocsJsonSerializerHelper.TryDeserialize(pureJson, out var section)) + { + throw new UserFriendlyException($"ERROR-20200327: Cannot validate JSON content for `{sectionName}`!"); + } + + return await Task.FromResult(section); + } + catch (Exception) + { + Logger.LogWarning("Unable to parse parameters of document."); + return new T(); + } + } + + protected static string RemoveOptionsJson(string document, params string[] sectionNames) + { + foreach (var sectionName in sectionNames) + { + var orgDocument = document; + + try + { + if (!HasJsonSection(document) || !document.Contains(sectionName)) + { + continue; + } + + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, jsonSection) = + GetJsonBeginEndIndexesAndPureJson(document, sectionName); + + if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) + { + continue; + } + + document = document.Remove( + jsonBeginningIndex - jsonSection.Opener.Length, + (jsonEndingIndex + jsonSection.Closer.Length) - (jsonBeginningIndex - jsonSection.Opener.Length) + ); + } + catch (Exception) + { + document = orgDocument; + } + } + + return document; + } + + protected static bool HasJsonSection(string document) + { + return DocsJsonSections.Any(section => document.Contains(section.Opener) && document.Contains(section.Closer)); + } + + protected static (int, int, string, DocsJsonSection) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) + { + foreach (var section in DocsJsonSections) + { + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = + section.GetJsonBeginEndIndexesAndPureJson(document, sectionName); + + if (jsonBeginningIndex >= 0 && jsonEndingIndex > 0 && !string.IsNullOrWhiteSpace(insideJsonSection)) + { + return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, section); + } + } + + return (-1, -1, "", null); + } + + protected static string SetPartialTemplates(string document, IReadOnlyCollection templates) + { + foreach (var section in DocsJsonSections) + { + document = section.SetPartialTemplates(document, templates); + } + + return document; + } + + protected class DocsJsonSection + { + public string Opener { get; } + public string Closer { get; } + + public DocsJsonSection(string opener, string closer) + { + Opener = opener; + Closer = closer; + } + + public (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) + { + var searchedIndex = 0; + + while (searchedIndex < document.Length) + { + var jsonBeginningIndex = document.Substring(searchedIndex).IndexOf(Opener, StringComparison.Ordinal); + + if (jsonBeginningIndex < 0) + { + return (-1, -1, ""); + } + + jsonBeginningIndex += Opener.Length + searchedIndex; + + var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(Closer, StringComparison.Ordinal); + if (jsonEndingIndex < 0) + { + return (-1, -1, ""); + } + + jsonEndingIndex += jsonBeginningIndex; + var insideJsonSection = document.Substring(jsonBeginningIndex, jsonEndingIndex - jsonBeginningIndex); + + if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0) + { + searchedIndex = jsonEndingIndex + Closer.Length; + continue; + } + + return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection); + } + + return (-1, -1, ""); + } + + public async Task> GetPartialTemplatesInDocumentAsync(string documentContent) + { + var templates = new List(); + + while (documentContent.Contains(Opener)) + { + var afterJsonOpener = documentContent.Substring( + documentContent.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); + + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + ); + + documentContent = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + + if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) + { + continue; + } + + var json = betweenJsonOpenerAndCloser.Substring( + betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + + DocsTemplates.Length); + + if (!DocsJsonSerializerHelper.TryDeserialize(json, + out var template)) + { + throw new UserFriendlyException( + $"ERROR-20200327: Cannot validate JSON content for `AvailableParameters`!"); + } + + templates.Add(template); + } + + return await Task.FromResult(templates); + } + + public string SetPartialTemplates(string document, IReadOnlyCollection templates) + { + var newDocument = new StringBuilder(); + + while (document.Contains(Opener)) + { + var beforeJson = document.Substring(0, + document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); + + var afterJsonOpener = document.Substring( + document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); + + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + ); + + if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) + { + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + + newDocument.Append(beforeJson + betweenJsonOpenerAndCloser + Closer); + continue; + } + + var json = betweenJsonOpenerAndCloser.Substring( + betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + + DocsTemplates.Length + ); + + if (DocsJsonSerializerHelper.TryDeserialize(json, + out var documentPartialTemplateWithValuesDto)) + { + var template = + templates.FirstOrDefault(t => t.Path == documentPartialTemplateWithValuesDto.Path); + + var beforeTemplate = document.Substring(0, + document.IndexOf(Opener, StringComparison.Ordinal) + ); + + newDocument.Append(beforeTemplate + template?.Content + Closer); + + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + } + } + + newDocument.Append(document); + + return newDocument.ToString(); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs index a4c4c7647e..e0a383e691 100644 --- a/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs @@ -1,6 +1,4 @@ using AutoMapper; -using Volo.Abp.AutoMapper; -using Volo.Docs.Documents; namespace Volo.Docs { @@ -8,7 +6,6 @@ namespace Volo.Docs { public DocsWebAutoMapperProfile() { - } } } diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs deleted file mode 100644 index d3ea14921c..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Docs.HtmlConverting -{ - public class DocumentPartialTemplateWithValuesDto - { - public string Path { get; set; } - - public Dictionary Parameters { get; set; } - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs deleted file mode 100644 index 7d9f26832f..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Docs.HtmlConverting -{ - public class DocumentRenderParameters : Dictionary - { - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs deleted file mode 100644 index 73560a7273..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace Volo.Docs.HtmlConverting -{ - public interface IDocumentSectionRenderer: ITransientDependency - { - Task RenderAsync(string doucment, DocumentRenderParameters parameters = null, List partialTemplates = null); - - Task>> GetAvailableParametersAsync(string document); - - Task> GetPartialTemplatesInDocumentAsync(string documentContent); - - Task GetDocumentNavigationsAsync(string documentContent); - } -} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs new file mode 100644 index 0000000000..b485c7b132 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Documents.Rendering; + +namespace Volo.Docs.HtmlConverting +{ + public interface IWebDocumentSectionRenderer: IDocumentSectionRenderer + { + Task> GetPartialTemplatesInDocumentAsync(string documentContent); + + Task GetDocumentNavigationsAsync(string documentContent); + } +} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs deleted file mode 100644 index e8d0149cf8..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Scriban; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Volo.Abp; -using Volo.Extensions; - -namespace Volo.Docs.HtmlConverting -{ - public class ScribanDocumentSectionRenderer : IDocumentSectionRenderer - { - private readonly static List DocsJsonSections = new List - { - new DocsJsonSection("````json", "````"), - new DocsJsonSection("```json", "```") - }; - private const string DocsParam = "//[doc-params]"; - private const string DocsTemplates = "//[doc-template]"; - private const string DocsNav = "//[doc-nav]"; - - public ILogger Logger { get; set; } - - public ScribanDocumentSectionRenderer() - { - Logger = NullLogger.Instance; - } - - public async Task RenderAsync(string document, DocumentRenderParameters parameters = null, List partialTemplates = null) - { - if (partialTemplates != null && partialTemplates.Any()) - { - document = SetPartialTemplates(document, partialTemplates); - } - - var scribanTemplate = Template.Parse(document); - - if (parameters == null) - { - return await scribanTemplate.RenderAsync(); - } - - var result = await scribanTemplate.RenderAsync(parameters); - - return RemoveOptionsJson(result, DocsParam, DocsNav); - } - - public Task>> GetAvailableParametersAsync(string document) - { - return GetSectionAsync>>(document, DocsParam); - } - - public Task GetDocumentNavigationsAsync(string documentContent) - { - return GetSectionAsync(documentContent, DocsNav); - } - - protected virtual async Task GetSectionAsync(string document, string sectionName) where T : new() - { - try - { - if (!HasJsonSection(document) || !document.Contains(sectionName)) - { - return new T(); - } - - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, _) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); - - if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) - { - return new T(); - } - - var pureJson = insideJsonSection.Replace(sectionName, "").Trim(); - - if (!DocsJsonSerializerHelper.TryDeserialize(pureJson, out var section)) - { - throw new UserFriendlyException($"ERROR-20200327: Cannot validate JSON content for `{sectionName}`!"); - } - - return await Task.FromResult(section); - } - catch (Exception) - { - Logger.LogWarning("Unable to parse parameters of document."); - return new T(); - } - } - - private static string RemoveOptionsJson(string document, params string[] sectionNames) - { - - foreach (var sectionName in sectionNames) - { - var orgDocument = document; - - try - { - if (!HasJsonSection(document) || !document.Contains(sectionName)) - { - continue; - } - - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, jsonSection) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); - - if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) - { - continue; - } - - document = document.Remove( - jsonBeginningIndex - jsonSection.Opener.Length, - (jsonEndingIndex + jsonSection.Closer.Length) - (jsonBeginningIndex - jsonSection.Opener.Length) - ); - } - catch (Exception) - { - document = orgDocument; - } - } - - return document; - } - - private static bool HasJsonSection(string document) - { - return DocsJsonSections.Any(section => document.Contains(section.Opener) && document.Contains(section.Closer)); - } - - private static (int, int, string, DocsJsonSection) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) - { - foreach (var section in DocsJsonSections) - { - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = section.GetJsonBeginEndIndexesAndPureJson(document, sectionName); - - if (jsonBeginningIndex >= 0 && jsonEndingIndex > 0 && !string.IsNullOrWhiteSpace(insideJsonSection)) - { - return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, section); - } - } - - return (-1, -1, "", null); - } - - public async Task> GetPartialTemplatesInDocumentAsync(string documentContent) - { - var templates = new List(); - - foreach (var section in DocsJsonSections) - { - templates.AddRange(await section.GetPartialTemplatesInDocumentAsync(documentContent)); - } - - return templates; - } - - private static string SetPartialTemplates(string document, IReadOnlyCollection templates) - { - foreach (var section in DocsJsonSections) - { - document = section.SetPartialTemplates(document, templates); - } - - return document; - } - - private class DocsJsonSection - { - public string Opener { get; } - public string Closer { get; } - - public DocsJsonSection(string opener, string closer) - { - Opener = opener; - Closer = closer; - } - - public (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) - { - var searchedIndex = 0; - - while (searchedIndex < document.Length) - { - var jsonBeginningIndex = document.Substring(searchedIndex).IndexOf(Opener, StringComparison.Ordinal); - - if (jsonBeginningIndex < 0) - { - return (-1, -1, ""); - } - - jsonBeginningIndex += Opener.Length + searchedIndex; - - var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(Closer, StringComparison.Ordinal); - if (jsonEndingIndex < 0) - { - return (-1, -1, ""); - } - - jsonEndingIndex += jsonBeginningIndex; - var insideJsonSection = document[jsonBeginningIndex..jsonEndingIndex]; - - if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0) - { - searchedIndex = jsonEndingIndex + Closer.Length; - continue; - } - - return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection); - } - - return (-1, -1, ""); - } - - public async Task> GetPartialTemplatesInDocumentAsync( - string documentContent) - { - var templates = new List(); - - while (documentContent.Contains(Opener)) - { - var afterJsonOpener = documentContent.Substring( - documentContent.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length - ); - - var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) - ); - - documentContent = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length - ); - - if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) - { - continue; - } - - var json = betweenJsonOpenerAndCloser.Substring( - betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + - DocsTemplates.Length); - - if (!DocsJsonSerializerHelper.TryDeserialize(json, - out var template)) - { - throw new UserFriendlyException( - $"ERROR-20200327: Cannot validate JSON content for `AvailableParameters`!"); - } - - templates.Add(template); - } - - return await Task.FromResult(templates); - } - - public string SetPartialTemplates(string document, - IReadOnlyCollection templates) - { - var newDocument = new StringBuilder(); - - while (document.Contains(Opener)) - { - var beforeJson = document.Substring(0, - document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length - ); - - var afterJsonOpener = document.Substring( - document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length - ); - - var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) - ); - - if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) - { - document = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length - ); - - newDocument.Append(beforeJson + betweenJsonOpenerAndCloser + Closer); - continue; - } - - var json = betweenJsonOpenerAndCloser.Substring( - betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + - DocsTemplates.Length - ); - - if (DocsJsonSerializerHelper.TryDeserialize(json, - out var documentPartialTemplateWithValuesDto)) - { - var template = - templates.FirstOrDefault(t => t.Path == documentPartialTemplateWithValuesDto.Path); - - var beforeTemplate = document.Substring(0, - document.IndexOf(Opener, StringComparison.Ordinal) - ); - - newDocument.Append(beforeTemplate + template?.Content + Closer); - - document = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length - ); - } - } - - newDocument.Append(document); - - return newDocument.ToString(); - } - } - } -} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs new file mode 100644 index 0000000000..e4a26b2df6 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Scriban; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp; +using Volo.Abp.ObjectMapping; +using Volo.Docs.Documents.Rendering; +using Volo.Extensions; + +namespace Volo.Docs.HtmlConverting +{ + public class ScribanWebDocumentSectionRenderer : ScribanDocumentSectionRenderer, IWebDocumentSectionRenderer + { + private IObjectMapper ObjectMapper { get; set; } + + public Task GetDocumentNavigationsAsync(string documentContent) + { + return GetSectionAsync(documentContent, DocsNav); + } + + public async Task> GetPartialTemplatesInDocumentAsync( + string documentContent) + { + var templates = new List(); + + foreach (var section in DocsJsonSections) + { + templates.AddRange(await section.GetPartialTemplatesInDocumentAsync(documentContent)); + } + + return templates; + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index 2bb7c82c21..c27e0d1f6f 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -19,6 +19,7 @@ using Volo.Abp.Data; using Volo.Abp.Domain.Entities; using Volo.Abp.EventBus.Local; using Volo.Docs.Documents; +using Volo.Docs.Documents.Rendering; using Volo.Docs.HtmlConverting; using Volo.Docs.Models; using Volo.Docs.Projects; @@ -96,7 +97,7 @@ namespace Volo.Docs.Pages.Documents.Project private readonly IDocumentAppService _documentAppService; private readonly IDocumentToHtmlConverterFactory _documentToHtmlConverterFactory; private readonly IProjectAppService _projectAppService; - private readonly IDocumentSectionRenderer _documentSectionRenderer; + private readonly IWebDocumentSectionRenderer _webDocumentSectionRenderer; private readonly DocsUiOptions _uiOptions; protected IDocsLinkGenerator DocsLinkGenerator => LazyServiceProvider.LazyGetRequiredService(); @@ -108,17 +109,16 @@ namespace Volo.Docs.Pages.Documents.Project IDocumentToHtmlConverterFactory documentToHtmlConverterFactory, IProjectAppService projectAppService, IOptions options, - IDocumentSectionRenderer documentSectionRenderer) + IWebDocumentSectionRenderer webDocumentSectionRenderer) { ObjectMapperContext = typeof(DocsWebModule); _documentAppService = documentAppService; _documentToHtmlConverterFactory = documentToHtmlConverterFactory; _projectAppService = projectAppService; - _documentSectionRenderer = documentSectionRenderer; + _webDocumentSectionRenderer = webDocumentSectionRenderer; _uiOptions = options.Value; - - + LocalizationResourceType = typeof(DocsResource); } @@ -561,11 +561,11 @@ namespace Volo.Docs.Pages.Documents.Project var partialTemplates = await GetDocumentPartialTemplatesAsync(); - DocumentNavigationsDto = await _documentSectionRenderer.GetDocumentNavigationsAsync(Document.Content); + DocumentNavigationsDto = await _webDocumentSectionRenderer.GetDocumentNavigationsAsync(Document.Content); try { - Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates); + Document.Content = await _webDocumentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates); } catch (Exception e) { @@ -619,7 +619,7 @@ namespace Volo.Docs.Pages.Documents.Project private async Task> GetDocumentPartialTemplatesAsync() { - var partialTemplatesInDocument = await _documentSectionRenderer.GetPartialTemplatesInDocumentAsync(Document.Content); + var partialTemplatesInDocument = await _webDocumentSectionRenderer.GetPartialTemplatesInDocumentAsync(Document.Content); if (!partialTemplatesInDocument?.Any(t => t.Parameters != null) ?? true) { @@ -772,7 +772,9 @@ namespace Volo.Docs.Pages.Documents.Project return; } - var availableParameters = await _documentSectionRenderer.GetAvailableParametersAsync(Document.Content); + var availableParameters = await _webDocumentSectionRenderer.GetAvailableParametersAsync(Document.Content); + var parameterCombinations = new List>(); + GenerateCombinations(0, availableParameters.Keys.ToList(),availableParameters,new Dictionary(), parameterCombinations); DocumentPreferences = new DocumentParametersDto { @@ -813,11 +815,32 @@ namespace Volo.Docs.Pages.Documents.Project { if (!DocumentPreferences?.Parameters?.Any() ?? true) { - return; + return; } AlternativeOptionLinkQueries = CollectAlternativeOptionLinksRecursively(); } + + void GenerateCombinations( + int keyIndex, + List parameterKeys , + Dictionary> parameters, + Dictionary currentCombination, + List> parameterCombinations ) + { + if (keyIndex == parameterKeys.Count) + { + parameterCombinations.Add(new Dictionary(currentCombination)); + return; + } + + var currentKey = parameterKeys[keyIndex]; + foreach (var value in parameters[currentKey]) + { + currentCombination[currentKey] = value; + GenerateCombinations(keyIndex + 1,parameterKeys, parameters, currentCombination,parameterCombinations); + } + } private List CollectAlternativeOptionLinksRecursively(int index = 0) { diff --git a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj index 1d6e0e1ace..2c36600107 100644 --- a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj +++ b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj @@ -23,7 +23,7 @@ - + From 41704ce265c5ad880ad787f4fe0524f3228130c9 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 17 Apr 2025 17:05:03 +0800 Subject: [PATCH 03/19] Export ABP documentation as PDF --- ....cs => 20250411070040_initial.Designer.cs} | 92 +- ...2_Initial.cs => 20250411070040_initial.cs} | 61 +- .../VoloDocsDbContextModelSnapshot.cs | 88 +- .../VoloDocs.EntityFrameworkCore.csproj | 1 + .../VoloDocsDbContext.cs | 2 + .../VoloDocsEntityFrameworkCoreModule.cs | 4 +- .../app/VoloDocs.Migrator/appsettings.json | 2 +- .../app/VoloDocs.Web/Pages/Index.cshtml.cs | 2 +- .../app/VoloDocs.Web/VoloDocsWebModule.cs | 14 +- .../docs/app/VoloDocs.Web/appsettings.json | 5 +- .../Docs/Admin/Projects/DeletePdfFileInput.cs | 12 + .../Admin/Projects/IProjectAdminAppService.cs | 2 + .../Admin/Projects/ProjectAdminAppService.cs | 13 +- .../ProjectsAdminClientProxy.Generated.cs | 8 + .../docs-admin-generate-proxy.json | 1109 +++++++++++++++++ .../Docs/Admin/ProjectsAdminController.cs | 7 + .../Docs/Admin/Projects/GeneratePdf.cshtml | 47 + .../Docs/Admin/Projects/GeneratePdf.cshtml.cs | 62 + .../Pages/Docs/Admin/Projects/Index.cshtml | 2 + .../Pages/Docs/Admin/Projects/generatePdf.js | 67 + .../Pages/Docs/Admin/Projects/index.js | 16 + .../client-proxies/docs-admin-proxy.js | 8 + .../client-proxies/docs-common-proxy.js | 68 + .../Volo.Docs.Application.Contracts.csproj | 1 + .../Docs/DocsApplicationContractsModule.cs | 2 + .../Docs/Documents/DocumentWithDetailsDto.cs | 1 + .../Volo.Docs.Application.csproj | 1 + .../Docs/DocsApplicationAutoMapperProfile.cs | 3 +- .../Volo/Docs/DocsApplicationModule.cs | 2 + .../Volo/Docs/Documents/DocumentAppService.cs | 1 + .../Common}/Projects/IProjectAppService.cs | 3 +- .../Volo/Docs/Common}/Projects/ProjectDto.cs | 2 +- .../Docs/Common}/Projects/VersionInfoDto.cs | 2 +- .../Volo.Docs.Common.Application.csproj | 6 - .../Docs/Common/DocsCommonAppServiceBase.cs | 14 + .../DocsCommonApplicationAutoMapperProfile.cs | 15 + .../Common/DocsCommonApplicationModule.cs | 14 +- .../DocumentPdfGeneratorAppService.cs | 18 +- .../Common}/Projects/ProjectAppService.cs | 7 +- ...cumentPdfGeneratorClientProxy.Generated.cs | 28 + .../DocsDocumentPdfGeneratorClientProxy.cs | 7 + .../DocsProjectClientProxy.Generated.cs | 2 +- .../Docs/Projects/DocsProjectClientProxy.cs | 0 .../docs-common-generate-proxy.json | 420 +++++++ .../Docs/DocsCommonHttpApiClientModule.cs | 25 + .../Docs/Projects/DocsProjectController.cs | 6 +- .../Volo/Docs/Projects/ProjectConsts.cs | 2 + .../Volo.Docs.Domain/Volo.Docs.Domain.csproj | 8 +- .../Volo/Docs/DocsDomainModule.cs | 7 +- .../Documents/Pdf/BlobDocumentPdfFileStore.cs | 50 + .../Documents/Pdf/DocsDocumentPdfCacheItem.cs | 11 + .../Pdf}/DocsDocumentPdfContainer.cs | 2 +- .../Pdf}/DocsDocumentPdfGeneratorOptions.cs | 26 +- .../Documents/Pdf}/DocumentPdfGenerator.cs | 150 +-- .../Documents/Pdf/IDocumentPdfFileStore.cs | 12 + .../Documents/Pdf}/IDocumentPdfGenerator.cs | 5 +- .../Volo/Docs/Documents/Pdf/IPdfRenderer.cs | 10 + .../Pdf/IText}/HtmlIdTagWorkerFactory.cs | 4 +- .../Documents/Pdf/IText/ITextPdfRenderer.cs | 73 ++ .../Docs/Documents/Pdf/PdfDocumentNode.cs | 16 + .../ClientProxies/docs-generate-proxy.json | 329 ++--- .../IDocumentToHtmlConverter.cs | 2 +- .../MarkdownDocumentToHtmlConverter.cs | 6 +- .../Pages/Documents/Index.cshtml.cs | 2 +- .../Pages/Documents/Project/Index.cshtml | 9 + .../Pages/Documents/Project/Index.cshtml.cs | 15 +- .../Pages/Documents/Project/index.css | 14 + .../Pages/Documents/Project/index.scss | 53 +- .../Pages/Documents/Search.cshtml.cs | 5 +- .../client-proxies/docs-common-proxy.js | 68 + .../wwwroot/client-proxies/docs-proxy.js | 35 +- .../Volo/Docs/ApplicationService_Tests.cs | 2 +- 72 files changed, 2767 insertions(+), 421 deletions(-) rename modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/{20241231072012_Initial.Designer.cs => 20250411070040_initial.Designer.cs} (93%) rename modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/{20241231072012_Initial.cs => 20250411070040_initial.cs} (93%) create mode 100644 modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs create mode 100644 modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json create mode 100644 modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml create mode 100644 modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml.cs create mode 100644 modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js create mode 100644 modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-common-proxy.js rename modules/docs/src/{Volo.Docs.Application.Contracts/Volo/Docs => Volo.Docs.Common.Application.Contracts/Volo/Docs/Common}/Projects/IProjectAppService.cs (90%) rename modules/docs/src/{Volo.Docs.Application.Contracts/Volo/Docs => Volo.Docs.Common.Application.Contracts/Volo/Docs/Common}/Projects/ProjectDto.cs (95%) rename modules/docs/src/{Volo.Docs.Application.Contracts/Volo/Docs => Volo.Docs.Common.Application.Contracts/Volo/Docs/Common}/Projects/VersionInfoDto.cs (77%) create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonAppServiceBase.cs create mode 100644 modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationAutoMapperProfile.cs rename modules/docs/src/{Volo.Docs.Application/Volo/Docs => Volo.Docs.Common.Application/Volo/Docs/Common}/Projects/ProjectAppService.cs (97%) create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.Generated.cs create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.cs rename modules/docs/src/{Volo.Docs.HttpApi.Client => Volo.Docs.Common.HttpApi.Client}/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs (98%) rename modules/docs/src/{Volo.Docs.HttpApi.Client => Volo.Docs.Common.HttpApi.Client}/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.cs (100%) create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/docs-common-generate-proxy.json create mode 100644 modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo/Docs/DocsCommonHttpApiClientModule.cs rename modules/docs/src/{Volo.Docs.HttpApi => Volo.Docs.Common.HttpApi}/Volo/Docs/Projects/DocsProjectController.cs (90%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs rename modules/docs/src/{Volo.Docs.Common.Application/Volo/Docs/Common/Documents => Volo.Docs.Domain/Volo/Docs/Documents/Pdf}/DocsDocumentPdfContainer.cs (74%) rename modules/docs/src/{Volo.Docs.Common.Application/Volo/Docs/Common/Documents => Volo.Docs.Domain/Volo/Docs/Documents/Pdf}/DocsDocumentPdfGeneratorOptions.cs (67%) rename modules/docs/src/{Volo.Docs.Common.Application/Volo/Docs/Common/Documents => Volo.Docs.Domain/Volo/Docs/Documents/Pdf}/DocumentPdfGenerator.cs (76%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfFileStore.cs rename modules/docs/src/{Volo.Docs.Common.Application/Volo/Docs/Common/Documents => Volo.Docs.Domain/Volo/Docs/Documents/Pdf}/IDocumentPdfGenerator.cs (57%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs rename modules/docs/src/{Volo.Docs.Common.Application/Volo/Docs/Common/Documents => Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText}/HtmlIdTagWorkerFactory.cs (92%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/PdfDocumentNode.cs create mode 100644 modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-common-proxy.js diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.Designer.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.Designer.cs similarity index 93% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.Designer.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.Designer.cs index ad7dfa9576..325052b498 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.Designer.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.Designer.cs @@ -13,8 +13,8 @@ using VoloDocs.EntityFrameworkCore; namespace Migrations { [DbContext(typeof(VoloDocsDbContext))] - [Migration("20241231072012_Initial")] - partial class Initial + [Migration("20250411070040_initial")] + partial class initial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -22,11 +22,88 @@ namespace Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("ProductVersion", "9.0.2") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -1119,6 +1196,15 @@ namespace Migrations b.ToTable("DocsProjects", (string)null); }); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => { b.HasOne("Volo.Abp.Identity.IdentityRole", null) diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.cs similarity index 93% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.cs index 25791fabf4..1c03234da9 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.cs @@ -6,11 +6,26 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace Migrations { /// - public partial class Initial : Migration + public partial class initial : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.CreateTable( + name: "AbpBlobContainers", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBlobContainers", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -336,6 +351,29 @@ namespace Migrations table.PrimaryKey("PK_DocsProjects", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpBlobs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ContainerId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Content = table.Column(type: "varbinary(max)", maxLength: 2147483647, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBlobs", x => x.Id); + table.ForeignKey( + name: "FK_AbpBlobs_AbpBlobContainers_ContainerId", + column: x => x.ContainerId, + principalTable: "AbpBlobContainers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "AbpOrganizationUnitRoles", columns: table => new @@ -520,6 +558,21 @@ namespace Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateIndex( + name: "IX_AbpBlobContainers_TenantId_Name", + table: "AbpBlobContainers", + columns: new[] { "TenantId", "Name" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpBlobs_ContainerId", + table: "AbpBlobs", + column: "ContainerId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpBlobs_TenantId_ContainerId_Name", + table: "AbpBlobs", + columns: new[] { "TenantId", "ContainerId", "Name" }); + migrationBuilder.CreateIndex( name: "IX_AbpLinkUsers_SourceUserId_SourceTenantId_TargetUserId_TargetTenantId", table: "AbpLinkUsers", @@ -668,6 +721,9 @@ namespace Migrations /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "AbpBlobs"); + migrationBuilder.DropTable( name: "AbpClaimTypes"); @@ -725,6 +781,9 @@ namespace Migrations migrationBuilder.DropTable( name: "DocsProjects"); + migrationBuilder.DropTable( + name: "AbpBlobContainers"); + migrationBuilder.DropTable( name: "AbpOrganizationUnits"); diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs index 17e18940bb..43a60ece76 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs @@ -19,11 +19,88 @@ namespace Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("ProductVersion", "9.0.2") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -1116,6 +1193,15 @@ namespace Migrations b.ToTable("DocsProjects", (string)null); }); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => { b.HasOne("Volo.Abp.Identity.IdentityRole", null) diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj index 38f85e7541..f7a6f89231 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj @@ -13,6 +13,7 @@ + diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs index fb6aca4e19..08ca58dd72 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Volo.Abp.BlobStoring.Database.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.PermissionManagement.EntityFrameworkCore; @@ -23,6 +24,7 @@ namespace VoloDocs.EntityFrameworkCore modelBuilder.ConfigureSettingManagement(); modelBuilder.ConfigureIdentity(); modelBuilder.ConfigureDocs(); + modelBuilder.ConfigureBlobStoring(); } } } diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs index 44acea9a58..f94ec123bf 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs @@ -1,4 +1,5 @@ -using Volo.Abp.EntityFrameworkCore.SqlServer; +using Volo.Abp.BlobStoring.Database.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.SqlServer; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.EntityFrameworkCore; @@ -12,6 +13,7 @@ namespace VoloDocs.EntityFrameworkCore typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), + typeof(BlobStoringDatabaseEntityFrameworkCoreModule), typeof(AbpEntityFrameworkCoreSqlServerModule))] public class VoloDocsEntityFrameworkCoreModule : AbpModule { diff --git a/modules/docs/app/VoloDocs.Migrator/appsettings.json b/modules/docs/app/VoloDocs.Migrator/appsettings.json index b554a47fed..91cbfffb2f 100644 --- a/modules/docs/app/VoloDocs.Migrator/appsettings.json +++ b/modules/docs/app/VoloDocs.Migrator/appsettings.json @@ -1,3 +1,3 @@ { - "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;TrustServerCertificate=True" + "ConnectionString": "Server=localhost;Database=VoloDocs;user=sa;password=admin@123456;TrustServerCertificate=True" } \ No newline at end of file diff --git a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs index c335612ec4..512900e637 100644 --- a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs +++ b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Options; using Volo.Docs; -using Volo.Docs.Projects; +using Volo.Docs.Common.Projects; namespace VoloDocs.Web.Pages { diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index cf864f1e50..a0996f51df 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -32,11 +32,14 @@ using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; using Volo.Abp.Account; +using Volo.Abp.BlobStoring; +using Volo.Abp.BlobStoring.Database; using Volo.Abp.PermissionManagement.HttpApi; using Volo.Abp.Validation.Localization; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Docs.Common.Documents; +using Volo.Docs.Documents.Pdf; namespace VoloDocs.Web { @@ -83,7 +86,7 @@ namespace VoloDocs.Web // options.SingleProjectMode.ProjectName = "abp"; // options.MultiLanguageMode = false; // }); - + Configure(options => { options.Enable = false; @@ -175,6 +178,15 @@ namespace VoloDocs.Web Configure(options => { options.BaseUrl = configuration["App:selfUrl"]; + options.CoverPagePath = "Index.md"; + }); + + Configure(options => + { + options.Containers.ConfigureDefault(container => + { + container.UseDatabase(); + }); }); } diff --git a/modules/docs/app/VoloDocs.Web/appsettings.json b/modules/docs/app/VoloDocs.Web/appsettings.json index 21a2883937..5a8ec7a2da 100644 --- a/modules/docs/app/VoloDocs.Web/appsettings.json +++ b/modules/docs/app/VoloDocs.Web/appsettings.json @@ -1,4 +1,7 @@ { + "App": { + "selfUrl": "https://localhost:5001" + }, "Kestrel": { "EndPoints": { "Https": { @@ -9,7 +12,7 @@ "Redis": { "Configuration": "127.0.0.1" }, - "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;TrustServerCertificate=True", + "ConnectionString": "Server=localhost;Database=VoloDocs;user=sa;password=admin@123456;TrustServerCertificate=True", "ElasticSearch": { "Url": "http://localhost:9200" }, diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs new file mode 100644 index 0000000000..074553cf46 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs @@ -0,0 +1,12 @@ +using System; + +namespace Volo.Docs.Admin.Projects; + +public class DeletePdfFileInput +{ + public Guid Id { 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.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs index 6f3d503f44..4503027bed 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs @@ -22,5 +22,7 @@ namespace Volo.Docs.Admin.Projects Task ReindexAllAsync(); Task> GetListWithoutDetailsAsync(); + + Task DeletePdfFileAsync(DeletePdfFileInput input); } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs index 3142b821d2..3ed75c4b84 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs @@ -5,10 +5,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; +using Volo.Abp.Caching; using Volo.Abp.Data; using Volo.Abp.Guids; +using Volo.Docs.Common.Documents; using Volo.Docs.Documents; using Volo.Docs.Documents.FullSearch.Elastic; +using Volo.Docs.Documents.Pdf; using Volo.Docs.Localization; using Volo.Docs.Projects; @@ -21,12 +24,14 @@ namespace Volo.Docs.Admin.Projects private readonly IDocumentRepository _documentRepository; private readonly IDocumentFullSearch _elasticSearchService; private readonly IGuidGenerator _guidGenerator; + private readonly IDistributedCache _documentPdfCache; public ProjectAdminAppService( IProjectRepository projectRepository, IDocumentRepository documentRepository, IDocumentFullSearch elasticSearchService, - IGuidGenerator guidGenerator) + IGuidGenerator guidGenerator, + IDistributedCache documentPdfCache) { ObjectMapperContext = typeof(DocsAdminApplicationModule); LocalizationResource = typeof(DocsResource); @@ -35,6 +40,7 @@ namespace Volo.Docs.Admin.Projects _documentRepository = documentRepository; _elasticSearchService = elasticSearchService; _guidGenerator = guidGenerator; + _documentPdfCache = documentPdfCache; } public virtual async Task> GetListAsync(PagedAndSortedResultRequestDto input) @@ -176,5 +182,10 @@ namespace Volo.Docs.Admin.Projects var projects = await _projectRepository.GetListWithoutDetailsAsync(); return ObjectMapper.Map, List>(projects); } + + public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) + { + await _documentPdfCache.RemoveAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(input.Id, input.Version, input.LanguageCode)); + } } } diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs index 54f1ec22d5..baaea015c3 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs @@ -68,6 +68,14 @@ public partial class ProjectsAdminClientProxy : ClientProxyBase>(nameof(GetListWithoutDetailsAsync)); } + public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) + { + await RequestAsync(nameof(DeletePdfFileAsync), new ClientProxyRequestTypeValue + { + { typeof(DeletePdfFileInput), input } + }); + } + public virtual async Task ReindexAsync(ReindexInput input) { await RequestAsync(nameof(ReindexAsync), new ClientProxyRequestTypeValue diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json new file mode 100644 index 0000000000..36f81f8d46 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json @@ -0,0 +1,1109 @@ +{ + "modules": { + "docs-admin": { + "rootPath": "docs-admin", + "remoteServiceName": "AbpDocsAdmin", + "controllers": { + "Volo.Docs.Admin.DocumentsAdminController": { + "controllerName": "DocumentsAdmin", + "controllerGroupName": "DocumentsAdmin", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Admin.DocumentsAdminController", + "interfaces": [ + { + "type": "Volo.Docs.Admin.Documents.IDocumentAdminAppService", + "name": "IDocumentAdminAppService", + "methods": [ + { + "name": "ClearCacheAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.ClearCacheInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.ClearCacheInput", + "typeSimple": "Volo.Docs.Admin.Documents.ClearCacheInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "PullAllAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.PullAllDocumentInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.PullAllDocumentInput", + "typeSimple": "Volo.Docs.Admin.Documents.PullAllDocumentInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "PullAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.PullDocumentInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.PullDocumentInput", + "typeSimple": "Volo.Docs.Admin.Documents.PullDocumentInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "GetAllAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.GetAllInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.GetAllInput", + "typeSimple": "Volo.Docs.Admin.Documents.GetAllInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + } + }, + { + "name": "RemoveFromCacheAsync", + "parametersOnMethod": [ + { + "name": "documentId", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "ReindexAsync", + "parametersOnMethod": [ + { + "name": "documentId", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "GetFilterItemsAsync", + "parametersOnMethod": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Documents.DocumentInfoDto]" + } + }, + { + "name": "GetProjectsAsync", + "parametersOnMethod": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Projects.ProjectWithoutDetailsDto]" + } + } + ] + } + ], + "actions": { + "ClearCacheAsyncByInput": { + "uniqueName": "ClearCacheAsyncByInput", + "name": "ClearCacheAsync", + "httpMethod": "POST", + "url": "api/docs/admin/documents/ClearCache", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.ClearCacheInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.ClearCacheInput", + "typeSimple": "Volo.Docs.Admin.Documents.ClearCacheInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Docs.Admin.Documents.ClearCacheInput", + "typeSimple": "Volo.Docs.Admin.Documents.ClearCacheInput", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "PullAllAsyncByInput": { + "uniqueName": "PullAllAsyncByInput", + "name": "PullAllAsync", + "httpMethod": "POST", + "url": "api/docs/admin/documents/PullAll", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.PullAllDocumentInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.PullAllDocumentInput", + "typeSimple": "Volo.Docs.Admin.Documents.PullAllDocumentInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Docs.Admin.Documents.PullAllDocumentInput", + "typeSimple": "Volo.Docs.Admin.Documents.PullAllDocumentInput", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "PullAsyncByInput": { + "uniqueName": "PullAsyncByInput", + "name": "PullAsync", + "httpMethod": "POST", + "url": "api/docs/admin/documents/Pull", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.PullDocumentInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.PullDocumentInput", + "typeSimple": "Volo.Docs.Admin.Documents.PullDocumentInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Docs.Admin.Documents.PullDocumentInput", + "typeSimple": "Volo.Docs.Admin.Documents.PullDocumentInput", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "GetAllAsyncByInput": { + "uniqueName": "GetAllAsyncByInput", + "name": "GetAllAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/GetAll", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Documents.GetAllInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Documents.GetAllInput", + "typeSimple": "Volo.Docs.Admin.Documents.GetAllInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Name", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "FileName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Format", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "CreationTimeMin", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "CreationTimeMax", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LastUpdatedTimeMin", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LastUpdatedTimeMax", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LastSignificantUpdateTimeMin", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LastSignificantUpdateTimeMax", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LastCachedTimeMin", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LastCachedTimeMax", + "jsonName": null, + "type": "System.DateTime?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Sorting", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "SkipCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "MaxResultCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "RemoveFromCacheAsyncByDocumentId": { + "uniqueName": "RemoveFromCacheAsyncByDocumentId", + "name": "RemoveFromCacheAsync", + "httpMethod": "PUT", + "url": "api/docs/admin/documents/RemoveDocumentFromCache", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "documentId", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "documentId", + "name": "documentId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "ReindexAsyncByDocumentId": { + "uniqueName": "ReindexAsyncByDocumentId", + "name": "ReindexAsync", + "httpMethod": "PUT", + "url": "api/docs/admin/documents/ReindexDocument", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "documentId", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "documentId", + "name": "documentId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "GetFilterItemsAsync": { + "uniqueName": "GetFilterItemsAsync", + "name": "GetFilterItemsAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/GetFilterItems", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Documents.DocumentInfoDto]" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "GetProjectsAsync": { + "uniqueName": "GetProjectsAsync", + "name": "GetProjectsAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/GetProjects", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Projects.ProjectWithoutDetailsDto]" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + } + } + }, + "Volo.Docs.Admin.ProjectsAdminController": { + "controllerName": "ProjectsAdmin", + "controllerGroupName": "ProjectsAdmin", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Admin.ProjectsAdminController", + "interfaces": [ + { + "type": "Volo.Docs.Admin.Projects.IProjectAdminAppService", + "name": "IProjectAdminAppService", + "methods": [ + { + "name": "GetListAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto, Volo.Abp.Ddd.Application.Contracts", + "type": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + } + }, + { + "name": "GetAsync", + "parametersOnMethod": [ + { + "name": "id", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Docs.Admin.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.ProjectDto" + } + }, + { + "name": "CreateAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.CreateProjectDto, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.CreateProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.CreateProjectDto", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Docs.Admin.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.ProjectDto" + } + }, + { + "name": "UpdateAsync", + "parametersOnMethod": [ + { + "name": "id", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.UpdateProjectDto, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.UpdateProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.UpdateProjectDto", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Docs.Admin.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.ProjectDto" + } + }, + { + "name": "DeleteAsync", + "parametersOnMethod": [ + { + "name": "id", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "ReindexAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.ReindexInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.ReindexInput", + "typeSimple": "Volo.Docs.Admin.Projects.ReindexInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "ReindexAllAsync", + "parametersOnMethod": [], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "GetListWithoutDetailsAsync", + "parametersOnMethod": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Projects.ProjectWithoutDetailsDto]" + } + }, + { + "name": "DeletePdfFileAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.DeletePdfFileInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "typeSimple": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + } + ] + } + ], + "actions": { + "GetListAsyncByInput": { + "uniqueName": "GetListAsyncByInput", + "name": "GetListAsync", + "httpMethod": "GET", + "url": "api/docs/admin/projects", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto, Volo.Abp.Ddd.Application.Contracts", + "type": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedAndSortedResultRequestDto", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "Sorting", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "SkipCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "MaxResultCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "GetAsyncById": { + "uniqueName": "GetAsyncById", + "name": "GetAsync", + "httpMethod": "GET", + "url": "api/docs/admin/projects/{id}", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "id", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "id", + "name": "id", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Docs.Admin.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.ProjectDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "CreateAsyncByInput": { + "uniqueName": "CreateAsyncByInput", + "name": "CreateAsync", + "httpMethod": "POST", + "url": "api/docs/admin/projects", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.CreateProjectDto, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.CreateProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.CreateProjectDto", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Docs.Admin.Projects.CreateProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.CreateProjectDto", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Docs.Admin.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.ProjectDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "UpdateAsyncByIdAndInput": { + "uniqueName": "UpdateAsyncByIdAndInput", + "name": "UpdateAsync", + "httpMethod": "PUT", + "url": "api/docs/admin/projects/{id}", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "id", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.UpdateProjectDto, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.UpdateProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.UpdateProjectDto", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "id", + "name": "id", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + }, + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Docs.Admin.Projects.UpdateProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.UpdateProjectDto", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Docs.Admin.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Admin.Projects.ProjectDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "DeleteAsyncById": { + "uniqueName": "DeleteAsyncById", + "name": "DeleteAsync", + "httpMethod": "DELETE", + "url": "api/docs/admin/projects", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "id", + "typeAsString": "System.Guid, System.Private.CoreLib", + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "id", + "name": "id", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "ReindexAllAsync": { + "uniqueName": "ReindexAllAsync", + "name": "ReindexAllAsync", + "httpMethod": "POST", + "url": "api/docs/admin/projects/ReindexAll", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "GetListWithoutDetailsAsync": { + "uniqueName": "GetListWithoutDetailsAsync", + "name": "GetListWithoutDetailsAsync", + "httpMethod": "GET", + "url": "api/docs/admin/projects/GetListProjectWithoutDetailsAsync", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Projects.ProjectWithoutDetailsDto]" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "DeletePdfFileAsyncByInput": { + "uniqueName": "DeletePdfFileAsyncByInput", + "name": "DeletePdfFileAsync", + "httpMethod": "DELETE", + "url": "api/docs/admin/projects/DeletePdfFile", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.DeletePdfFileInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "typeSimple": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "Id", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, + "ReindexAsyncByInput": { + "uniqueName": "ReindexAsyncByInput", + "name": "ReindexAsync", + "httpMethod": "POST", + "url": "api/docs/admin/projects/Reindex", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.ReindexInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.ReindexInput", + "typeSimple": "Volo.Docs.Admin.Projects.ReindexInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Docs.Admin.Projects.ReindexInput", + "typeSimple": "Volo.Docs.Admin.Projects.ReindexInput", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + } + } + } + } + } + }, + "types": {} +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs index 5b1cffeae1..f4ac744f76 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs @@ -70,6 +70,13 @@ namespace Volo.Docs.Admin return _projectAppService.GetListWithoutDetailsAsync(); } + [HttpDelete] + [Route("DeletePdfFile")] + public Task DeletePdfFileAsync(DeletePdfFileInput input) + { + return _projectAppService.DeletePdfFileAsync(input); + } + [HttpPost] [Route("Reindex")] public Task ReindexAsync(ReindexInput input) diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml new file mode 100644 index 0000000000..7eda48cf29 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml @@ -0,0 +1,47 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Docs.Admin.Pages.Docs.Admin.Projects; +@using Volo.Docs.Localization +@model GeneratePdfModal +@inject IHtmlLocalizer L +@{ + Layout = null; +} + + + + + + +
+ + +
+
+ + +
+
+ +
+
+ + + + + +
\ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml.cs b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml.cs new file mode 100644 index 0000000000..ffd189546c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using Volo.Docs.Admin.Projects; +using Volo.Docs.Common.Documents; +using Volo.Docs.Common.Projects; +using Volo.Docs.Projects; + +namespace Volo.Docs.Admin.Pages.Docs.Admin.Projects; + +public class GeneratePdfModal : DocsAdminPageModel +{ + protected IDocumentPdfGeneratorAppService DocumentPdfGeneratorAppService { get; } + protected IProjectAppService ProjectAppService { get; } + protected IProjectAdminAppService ProjectAdminAppService { get; } + + public GeneratePdfViewModel ViewModel { get; set; } + + public GeneratePdfModal( + IDocumentPdfGeneratorAppService documentPdfGeneratorAppService, + IProjectAppService projectAppService, + IProjectAdminAppService projectAdminAppService) + { + DocumentPdfGeneratorAppService = documentPdfGeneratorAppService; + ProjectAppService = projectAppService; + ProjectAdminAppService = projectAdminAppService; + } + + public virtual async Task OnGetAsync(Guid id) + { + var project = await ProjectAdminAppService.GetAsync(id); + var versions = await ProjectAppService.GetVersionsAsync(project.ShortName); + if(versions.Items.Count == 0) + { + versions.Items = + [ + new VersionInfoDto { Name = ProjectConsts.Latest, DisplayName = ProjectConsts.Latest } + ]; + } + var languages = await ProjectAppService.GetLanguageListAsync(project.ShortName, versions.Items.FirstOrDefault()?.Name); + ViewModel = new GeneratePdfViewModel + { + ProjectId = id, + ShortName = project.ShortName, + Versions = versions.Items.Select(x => new SelectListItem(x.DisplayName, x.Name)).ToList(), + Languages = languages.Languages.Select(x => new SelectListItem(x.DisplayName, x.Code)).ToList() + }; + + return Page(); + } + + public class GeneratePdfViewModel + { + public Guid ProjectId { get; set; } + public string ShortName { get; set; } + public List Versions { get; set; } + public List Languages { get; set; } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml index 07582a45dd..b80d2d76db 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml @@ -20,10 +20,12 @@ @section scripts { + + } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js new file mode 100644 index 0000000000..7be870f6b6 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js @@ -0,0 +1,67 @@ +var abp = abp || {}; +$(function () { + abp.modals.projectGeneratePdf = function () { + + var projectAppService = volo.docs.projects.docsProject; + var pdfGeneratorAppService = volo.docs.documents.docsDocumentPdfGenerator; + var projectAdminAppService = volo.docs.admin.projectsAdmin; + + var initModal = function (publicApi, args) { + + }; + + $("#Versions").change(function () { + var shortname = $("#ShortName").val(); + var version = $("#Version").val(); + projectAppService.getLanguageList(shortname, version).done(function (result) { + $("#Language").empty(); + $.each(result.languages, function (index, item) { + $("#Language").append($(``)); + }); + }); + }) + + $("#GeneratePdfBtn").click(function () { + var $btn = $(this); + $btn.buttonBusy(true); + var input = { + projectId: $("#ProjectId").val(), + version: $("#Version").val(), + languageCode: $("#Language").val(), + } + tryDeletePdfFile(input); + pdfGeneratorAppService.generatePdf(input, { + abpHandleError : false, + error: function (jqXHR) { + if (jqXHR.status === 200) { + abp.message.success("PDF generated successfully."); + $btn.buttonBusy(false); + } else { + abp.ajax.handleErrorStatusCode(jqXHR.status); + } + } + }); + }) + + $("#GenerateAndDownloadPdfBtn").click(function () { + var input = { + projectId: $("#ProjectId").val(), + version: $("#Version").val(), + languageCode: $("#Language").val(), + } + tryDeletePdfFile(input); + window.open(abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]), '_blank'); + }) + + function tryDeletePdfFile(input) { + var forceToGenerate = $("#ForceToGenerate").is(":checked"); + if(forceToGenerate) { + projectAdminAppService.deletePdfFile(input); + } + } + + return { + initModal: initModal, + }; + }; +}); diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js index cf11d50603..a362435088 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js @@ -16,6 +16,11 @@ $(function () { modalClass: 'projectPull', }); + var _generatePdfModal = new abp.ModalManager({ + viewUrl: abp.appPath + 'Docs/Admin/Projects/GeneratePdf', + modalClass: 'projectGeneratePdf', + }); + var _dataTable = $('#ProjectsTable').DataTable( abp.libs.datatables.normalizeConfiguration({ processing: true, @@ -117,6 +122,17 @@ $(function () { }); }, }, + { + text: l('GeneratePdf'), + visible: abp.auth.isGranted( + 'Docs.Admin.Documents' + ), + action: function (data) { + _generatePdfModal.open({ + Id: data.record.id, + }); + } + } ], }, }, diff --git a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js index 3a1c6930cf..9afc61c17e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js @@ -136,6 +136,14 @@ }, ajaxParams)); }; + volo.docs.admin.projectsAdmin.deletePdfFile = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/admin/projects/DeletePdfFile' + abp.utils.buildQueryString([{ name: 'id', value: input.id }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'DELETE', + dataType: null + }, ajaxParams)); + }; + volo.docs.admin.projectsAdmin.reindex = function(input, ajaxParams) { return abp.ajax($.extend(true, { url: abp.appPath + 'api/docs/admin/projects/Reindex', diff --git a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-common-proxy.js b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-common-proxy.js new file mode 100644 index 0000000000..014e357cba --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-common-proxy.js @@ -0,0 +1,68 @@ +/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */ + + +// module docs-common + +(function(){ + + // controller volo.docs.documents.docsDocumentPdfGenerator + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.documents.docsDocumentPdfGenerator'); + + volo.docs.documents.docsDocumentPdfGenerator.generatePdf = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + })(); + + // controller volo.docs.projects.docsProject + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.projects.docsProject'); + + volo.docs.projects.docsProject.getList = function(ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.get = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getDefaultLanguageCode = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/defaultLanguage' + abp.utils.buildQueryString([{ name: 'version', value: version }]) + '', + type: 'GET' + }, { dataType: 'text' }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getVersions = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/versions', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getLanguageList = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/' + version + '/languageList', + type: 'GET' + }, ajaxParams)); + }; + + })(); + +})(); + + diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj b/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj index d6d7c37d07..d7bb3b17b1 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj @@ -11,6 +11,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs index 7a3b9e9ec2..ce00f1a75a 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs @@ -1,10 +1,12 @@ using Volo.Abp.Application; using Volo.Abp.Modularity; +using Volo.Docs.Common; namespace Volo.Docs { [DependsOn( typeof(DocsDomainSharedModule), + typeof(DocsCommonApplicationContractsModule), typeof(AbpDddApplicationContractsModule) )] public class DocsApplicationContractsModule : AbpModule diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs index 0364a2e26f..5f559c83e5 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Volo.Docs.Common.Projects; using Volo.Docs.Projects; namespace Volo.Docs.Documents diff --git a/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj b/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj index 0bbf42da7e..b7530d7fe8 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj +++ b/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj @@ -12,6 +12,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs index fc2eec1759..f2cb5476f7 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs @@ -1,7 +1,8 @@ using AutoMapper; using Volo.Docs.Documents; -using Volo.Docs.Projects; using Volo.Abp.AutoMapper; +using Volo.Docs.Common.Projects; +using Volo.Docs.Projects; namespace Volo.Docs { diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs index e6826d54e6..f6d60099ad 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs @@ -4,6 +4,7 @@ using Volo.Abp.Application; using Volo.Abp.AutoMapper; using Volo.Abp.Caching; using Volo.Abp.Modularity; +using Volo.Docs.Common; using Volo.Docs.Documents; namespace Volo.Docs @@ -13,6 +14,7 @@ namespace Volo.Docs typeof(DocsApplicationContractsModule), typeof(AbpCachingModule), typeof(AbpAutoMapperModule), + typeof(DocsCommonApplicationModule), typeof(AbpDddApplicationModule) )] public class DocsApplicationModule : AbpModule diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs index c426afacbd..c156b669dd 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs @@ -14,6 +14,7 @@ using Volo.Abp.Application.Dtos; using Volo.Abp.Caching; using Volo.Abp.Data; using Volo.Docs.Caching; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Docs.Projects; using Volo.Extensions; diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/IProjectAppService.cs similarity index 90% rename from modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs rename to modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/IProjectAppService.cs index b93fb09e77..b81637c25f 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/IProjectAppService.cs @@ -2,8 +2,9 @@ using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Docs.Documents; +using Volo.Docs.Projects; -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { public interface IProjectAppService : IApplicationService { diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/ProjectDto.cs similarity index 95% rename from modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs rename to modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/ProjectDto.cs index 2861e60307..5e0890cbe5 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/ProjectDto.cs @@ -2,7 +2,7 @@ using System; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { [Serializable] public class ProjectDto : EntityDto, IHasExtraProperties diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/VersionInfoDto.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/VersionInfoDto.cs similarity index 77% rename from modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/VersionInfoDto.cs rename to modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/VersionInfoDto.cs index 32ac7bb1c4..59db11e3fa 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/VersionInfoDto.cs +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/VersionInfoDto.cs @@ -1,4 +1,4 @@ -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { public class VersionInfoDto { 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 index fa4173f985..545995b902 100644 --- 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 @@ -16,11 +16,5 @@ - - - - - - diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonAppServiceBase.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonAppServiceBase.cs new file mode 100644 index 0000000000..280a0c7c82 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonAppServiceBase.cs @@ -0,0 +1,14 @@ +using Volo.Abp.Application.Services; +using Volo.Docs.Localization; + +namespace Volo.Docs.Common +{ + public abstract class DocsCommonAppServiceBase : ApplicationService + { + protected DocsCommonAppServiceBase() + { + ObjectMapperContext = typeof(DocsCommonApplicationModule); + LocalizationResource = typeof(DocsResource); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationAutoMapperProfile.cs new file mode 100644 index 0000000000..8175654743 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationAutoMapperProfile.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using Volo.Docs.Common.Projects; +using Volo.Docs.Projects; + +namespace Volo.Docs.Common +{ + public class DocsCommonApplicationAutoMapperProfile : Profile + { + public DocsCommonApplicationAutoMapperProfile() + { + CreateMap(); + CreateMap(); + } + } +} 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 index 16f93808d2..b7eb350930 100644 --- 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 @@ -1,18 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; 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) )] @@ -20,6 +15,11 @@ public class DocsCommonApplicationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); } } \ 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 index cc752d1492..c51f9366b3 100644 --- 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 @@ -1,7 +1,9 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Services; +using Volo.Abp.BlobStoring; using Volo.Abp.Content; +using Volo.Docs.Documents.Pdf; using Volo.Docs.Projects; namespace Volo.Docs.Common.Documents; @@ -9,20 +11,20 @@ namespace Volo.Docs.Common.Documents; [Authorize(DocsCommonPermissions.Documents.PdfGeneration)] public class DocumentPdfGeneratorAppService : ApplicationService, IDocumentPdfGeneratorAppService { - private readonly IDocumentPdfGenerator _documentPdfGenerator; - private readonly IProjectRepository _projectRepository; - + protected IDocumentPdfGenerator DocumentPdfGenerator { get; } + protected IProjectRepository ProjectRepository { get; } + public DocumentPdfGeneratorAppService( IDocumentPdfGenerator documentPdfGenerator, IProjectRepository projectRepository) { - _documentPdfGenerator = documentPdfGenerator; - _projectRepository = projectRepository; + DocumentPdfGenerator = documentPdfGenerator; + ProjectRepository = projectRepository; } - public async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + public virtual async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) { - var project = await _projectRepository.GetAsync(input.ProjectId); - return await _documentPdfGenerator.GenerateAsync(project, input.Version, input.LanguageCode); + var project = await ProjectRepository.GetAsync(input.ProjectId); + return await DocumentPdfGenerator.GenerateAsync(project, input.Version, input.LanguageCode); } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Projects/ProjectAppService.cs similarity index 97% rename from modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs rename to modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Projects/ProjectAppService.cs index 1cca1a102a..96634a300e 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Projects/ProjectAppService.cs @@ -4,16 +4,15 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; using Volo.Abp.Application.Dtos; -using Volo.Abp.Application.Services; using Volo.Abp.Caching; using Volo.Abp.Data; -using Volo.Abp.Guids; using Volo.Docs.Caching; using Volo.Docs.Documents; +using Volo.Docs.Projects; -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { - public class ProjectAppService : DocsAppServiceBase, IProjectAppService + public class ProjectAppService : DocsCommonAppServiceBase, IProjectAppService { private readonly IProjectRepository _projectRepository; private readonly IDistributedCache> _versionCache; diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.Generated.cs new file mode 100644 index 0000000000..39608380c5 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.Generated.cs @@ -0,0 +1,28 @@ +// This file is automatically generated by ABP framework to use MVC Controllers from CSharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Modeling; +using Volo.Docs.Common.Documents; + +// ReSharper disable once CheckNamespace +namespace Volo.Docs.Documents; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(IDocumentPdfGeneratorAppService), typeof(DocsDocumentPdfGeneratorClientProxy))] +public partial class DocsDocumentPdfGeneratorClientProxy : ClientProxyBase, IDocumentPdfGeneratorAppService +{ + public virtual async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + { + return await RequestAsync(nameof(GeneratePdfAsync), new ClientProxyRequestTypeValue + { + { typeof(DocumentPdfGeneratorInput), input } + }); + } +} diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.cs new file mode 100644 index 0000000000..e14c1c25be --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentPdfGeneratorClientProxy.cs @@ -0,0 +1,7 @@ +// This file is part of DocsDocumentPdfGeneratorClientProxy, you can customize it here +// ReSharper disable once CheckNamespace +namespace Volo.Docs.Documents; + +public partial class DocsDocumentPdfGeneratorClientProxy +{ +} diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs similarity index 98% rename from modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs rename to modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs index 2caa2e3e93..19170e497e 100644 --- a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs @@ -8,8 +8,8 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client; using Volo.Abp.Http.Client.ClientProxying; using Volo.Abp.Http.Modeling; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; -using Volo.Docs.Projects; // ReSharper disable once CheckNamespace namespace Volo.Docs.Projects; diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.cs similarity index 100% rename from modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.cs rename to modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.cs diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/docs-common-generate-proxy.json b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/docs-common-generate-proxy.json new file mode 100644 index 0000000000..db7303a427 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/docs-common-generate-proxy.json @@ -0,0 +1,420 @@ +{ + "modules": { + "docs-common": { + "rootPath": "docs-common", + "remoteServiceName": "AbpDocsCommon", + "controllers": { + "Volo.Docs.Documents.DocsDocumentPdfGeneratorController": { + "controllerName": "DocsDocumentPdfGenerator", + "controllerGroupName": "Document", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Documents.DocsDocumentPdfGeneratorController", + "interfaces": [ + { + "type": "Volo.Docs.Common.Documents.IDocumentPdfGeneratorAppService", + "name": "IDocumentPdfGeneratorAppService", + "methods": [ + { + "name": "GeneratePdfAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Content.IRemoteStreamContent", + "typeSimple": "Volo.Abp.Content.IRemoteStreamContent" + } + } + ] + } + ], + "actions": { + "GeneratePdfAsyncByInput": { + "uniqueName": "GeneratePdfAsyncByInput", + "name": "GeneratePdfAsync", + "httpMethod": "GET", + "url": "api/docs/documents/pdf", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Content.IRemoteStreamContent", + "typeSimple": "Volo.Abp.Content.IRemoteStreamContent" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Documents.IDocumentPdfGeneratorAppService" + } + } + }, + "Volo.Docs.Projects.DocsProjectController": { + "controllerName": "DocsProject", + "controllerGroupName": "Project", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Projects.DocsProjectController", + "interfaces": [ + { + "type": "Volo.Docs.Common.Projects.IProjectAppService", + "name": "IProjectAppService", + "methods": [ + { + "name": "GetListAsync", + "parametersOnMethod": [], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + }, + { + "name": "GetAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Docs.Common.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Common.Projects.ProjectDto" + } + }, + { + "name": "GetVersionsAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + }, + { + "name": "GetDefaultLanguageCodeAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.String", + "typeSimple": "string" + } + }, + { + "name": "GetLanguageListAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Docs.Documents.LanguageConfig", + "typeSimple": "Volo.Docs.Documents.LanguageConfig" + } + } + ] + } + ], + "actions": { + "GetListAsync": { + "uniqueName": "GetListAsync", + "name": "GetListAsync", + "httpMethod": "GET", + "url": "api/docs/projects", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetAsyncByShortName": { + "uniqueName": "GetAsyncByShortName", + "name": "GetAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Docs.Common.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Common.Projects.ProjectDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetDefaultLanguageCodeAsyncByShortNameAndVersion": { + "uniqueName": "GetDefaultLanguageCodeAsyncByShortNameAndVersion", + "name": "GetDefaultLanguageCodeAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}/defaultLanguage", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + }, + { + "nameOnMethod": "version", + "name": "version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.String", + "typeSimple": "string" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetVersionsAsyncByShortName": { + "uniqueName": "GetVersionsAsyncByShortName", + "name": "GetVersionsAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}/versions", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetLanguageListAsyncByShortNameAndVersion": { + "uniqueName": "GetLanguageListAsyncByShortNameAndVersion", + "name": "GetLanguageListAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}/{version}/languageList", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + }, + { + "nameOnMethod": "version", + "name": "version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Docs.Documents.LanguageConfig", + "typeSimple": "Volo.Docs.Documents.LanguageConfig" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + } + } + } + } + } + }, + "types": {} +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo/Docs/DocsCommonHttpApiClientModule.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo/Docs/DocsCommonHttpApiClientModule.cs new file mode 100644 index 0000000000..a139d29ac2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo/Docs/DocsCommonHttpApiClientModule.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; +using Volo.Docs.Common; + +namespace Volo.Docs +{ + [DependsOn( + typeof(DocsCommonApplicationContractsModule), + typeof(AbpHttpClientModule) + )] + public class DocsCommonHttpApiClientModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddStaticHttpClientProxies(typeof(DocsCommonApplicationContractsModule).Assembly, DocsCommonRemoteServiceConsts.RemoteServiceName); + + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } + } +} diff --git a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Projects/DocsProjectController.cs similarity index 90% rename from modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs rename to modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Projects/DocsProjectController.cs index 3a23d379ef..440a215187 100644 --- a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Projects/DocsProjectController.cs @@ -5,12 +5,14 @@ using Asp.Versioning; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; +using Volo.Docs.Common; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; namespace Volo.Docs.Projects { - [RemoteService(Name = DocsRemoteServiceConsts.RemoteServiceName)] - [Area(DocsRemoteServiceConsts.ModuleName)] + [RemoteService(Name = DocsCommonRemoteServiceConsts.RemoteServiceName)] + [Area(DocsCommonRemoteServiceConsts.ModuleName)] [ControllerName("Project")] [Route("api/docs/projects")] public class DocsProjectController : AbpControllerBase, IProjectAppService diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs index 3322fb7732..b421cfc631 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs @@ -36,5 +36,7 @@ /// Default value: 128 /// public static int MaxVersionNameLength { get; set; } = 128; + + public static string Latest = "latest"; } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj index 5f2c9b6206..0dc06c6d56 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj +++ b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj @@ -20,7 +20,12 @@ - + + + + + +
@@ -28,6 +33,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs index 6e6b222351..c9fb4cb6f7 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs @@ -1,10 +1,11 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp; using Volo.Abp.AutoMapper; +using Volo.Abp.BlobStoring; +using Volo.Abp.Caching; using Volo.Abp.Domain; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Localization; @@ -24,7 +25,9 @@ namespace Volo.Docs [DependsOn( typeof(DocsDomainSharedModule), typeof(AbpDddDomainModule), - typeof(AbpAutoMapperModule) + typeof(AbpAutoMapperModule), + typeof(AbpBlobStoringModule), + typeof(AbpCachingModule) )] public class DocsDomainModule : AbpModule { diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs new file mode 100644 index 0000000000..9ddb076d3b --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; +using Volo.Abp.BlobStoring; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Projects; + +namespace Volo.Docs.Documents.Pdf; + +public class BlobDocumentPdfFileStore : IDocumentPdfFileStore, ITransientDependency +{ + protected IBlobContainer BlobContainer { get; } + protected IDistributedCache Cache { get; } + protected IOptions Options { get; } + + public BlobDocumentPdfFileStore( + IBlobContainer blobContainer, + IDistributedCache cache, + IOptions options) + { + BlobContainer = blobContainer; + Cache = cache; + Options = options; + } + + public virtual async Task SetAsync(Project project, string version, string languageCode, Stream stream) + { + await BlobContainer.SaveAsync(Options.Value.CalculatePdfFileName(project, version, languageCode), stream); + + await Cache.SetAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(project.Id, version, languageCode), new DocsDocumentPdfCacheItem(), + new DistributedCacheEntryOptions + { + AbsoluteExpiration = DateTimeOffset.Now.Add(Options.Value.PdfFileCacheExpiration) + }); + } + + public virtual async Task GetOrNullAsync(Project project, string version, string languageCode) + { + var cache = await Cache.GetAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(project.Id, version, languageCode)); + if (cache == null) + { + return null; + } + + return await BlobContainer.GetOrNullAsync(Options.Value.CalculatePdfFileName(project, version, languageCode)); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs new file mode 100644 index 0000000000..3763446e83 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs @@ -0,0 +1,11 @@ +using System; + +namespace Volo.Docs.Documents.Pdf; + +public class DocsDocumentPdfCacheItem +{ + public static string CalculateCacheKey(Guid projectId, string version, string languageCode) + { + return $"{projectId}_{version}_{languageCode}"; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfContainer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfContainer.cs similarity index 74% rename from modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfContainer.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfContainer.cs index 63e3652a3b..9a6e13f4ba 100644 --- a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfContainer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfContainer.cs @@ -1,6 +1,6 @@ using Volo.Abp.BlobStoring; -namespace Volo.Docs.Common.Documents; +namespace Volo.Docs.Documents.Pdf; [BlobContainerName("docs-document-pdf")] public class DocsDocumentPdfContainer diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs similarity index 67% rename from modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfGeneratorOptions.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs index 6d2ff2bc82..606eef2d4a 100644 --- a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocsDocumentPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs @@ -1,24 +1,38 @@ -namespace Volo.Docs.Common.Documents; +using System; +using Volo.Docs.Projects; + +namespace Volo.Docs.Documents.Pdf; public class DocsDocumentPdfGeneratorOptions { + public const string StylePlaceholder = "{{style-placeholder}}"; + public const string ContentPlaceholder = "{{content-placeholder}}"; + + /// + /// The HTML layout for the PDF document. + /// public string HtmlLayout { get; set; } public string HtmlStyles { get; set; } - public string BaseUrl { get; set; } - + public string CoverPagePath { get; set; } + public TimeSpan PdfFileCacheExpiration { get; set; } = TimeSpan.FromDays(1); + public Func CalculatePdfFileName { get; set; } = (project, version, languageCode) => + { + return $"{project.ShortName}_{version}_{languageCode}.pdf"; + }; + public DocsDocumentPdfGeneratorOptions() { - HtmlLayout = @" + HtmlLayout = $@" - {{content-placeholder}} + {ContentPlaceholder} "; diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs similarity index 76% rename from modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGenerator.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs index f54eafe116..fea0d488b4 100644 --- a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs @@ -4,62 +4,82 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using System.Web; -using iText.Html2pdf; -using iText.Kernel.Pdf; -using iText.Kernel.Pdf.Action; using Markdig; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp; using Volo.Abp.Content; -using Volo.Docs.Documents; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; +using Volo.Docs.Documents.Pdf.IText; using Volo.Docs.Documents.Rendering; using Volo.Docs.Projects; using Volo.Extensions; -using ITextDocument = iText.Layout.Document; -namespace Volo.Docs.Common.Documents; +namespace Volo.Docs.Documents.Pdf; -public class DocumentPdfGenerator : IDocumentPdfGenerator +public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency { protected IDocumentSourceFactory DocumentStoreFactory { get; } protected IDocumentRepository DocumentRepository { get; } protected IDocumentSectionRenderer DocumentSectionRenderer { get; } - protected IOptions Options { get; } + protected IOptions Options { get; } + protected IDocumentPdfFileStore DocumentPdfFileStore { get; } + protected IPdfRenderer PdfRenderer { get; } protected ILogger Logger { get; set; } protected IDocumentSource DocumentSource { get; set; } protected DocumentParams DocumentParams { get; set; } - protected List AllPdfDocumentNodes { get; set; } = new(); + protected List AllPdfDocumentNodes { get; set; } = []; protected MarkdownPipeline MarkdownPipeline { get; } = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build(); + + private readonly SemaphoreSlim _syncSemaphore; public DocumentPdfGenerator( IDocumentSourceFactory documentStoreFactory, IDocumentRepository documentRepository, IOptions options, - IDocumentSectionRenderer documentSectionRenderer) + IDocumentSectionRenderer documentSectionRenderer, + IDocumentPdfFileStore documentPdfFileStore, + IPdfRenderer pdfRenderer) { DocumentStoreFactory = documentStoreFactory; DocumentRepository = documentRepository; Options = options; DocumentSectionRenderer = documentSectionRenderer; + DocumentPdfFileStore = documentPdfFileStore; + PdfRenderer = pdfRenderer; Logger = NullLogger.Instance; + _syncSemaphore = new SemaphoreSlim(1, 1); } public virtual async Task GenerateAsync(Project project, string version, string languageCode) { - DocumentSource = DocumentStoreFactory.Create(project.DocumentStoreType); - DocumentParams = await GetDocumentParamsAsync(project, version, languageCode); - var navigation = await GetNavigationAsync(project, version, languageCode); + using (await _syncSemaphore.LockAsync()) + { + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + var fileStream = await DocumentPdfFileStore.GetOrNullAsync(project, version, languageCode); + + if (fileStream != null) + { + return new RemoteStreamContent(fileStream, fileName, "application/pdf"); + } + + DocumentSource = DocumentStoreFactory.Create(project.DocumentStoreType); + DocumentParams = await GetDocumentParamsAsync(project, version, languageCode); + var navigation = await GetNavigationAsync(project, version, languageCode); - await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode); - var htmlContent = await ConvertDocumentsToHtmlAsync(AllPdfDocumentNodes); + await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode); + var htmlContent = await ConvertDocumentsToHtmlAsync(AllPdfDocumentNodes); - var pdfStream = await GeneratePdfAsync(htmlContent); + var pdfStream = await PdfRenderer.GeneratePdfAsync(htmlContent, AllPdfDocumentNodes); + await DocumentPdfFileStore.SetAsync(project, version, languageCode, pdfStream); - return new RemoteStreamContent(pdfStream, CalculateDocumentPdfFileName(project.ShortName, version, languageCode), "application/pdf"); + return new RemoteStreamContent(pdfStream, fileName, "application/pdf"); + } } protected virtual async Task ConvertDocumentsToHtmlAsync(List pdfDocumentNodes) @@ -84,56 +104,6 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator return contentBuilder.ToString(); } - protected virtual Task GeneratePdfAsync(string htmlContent) - { - var pdfStream = new MemoryStream(); - var pdfWrite = new PdfWriter(pdfStream); - var pdfDocument = new PdfDocument(pdfWrite); - var textDocument = new ITextDocument(pdfDocument); - pdfWrite.SetCloseStream(false); - - var htmlBuilder = new StringBuilder(); - htmlBuilder.Append(Options.Value.HtmlLayout); - htmlBuilder.Replace("{{style-placeholder}}", Options.Value.HtmlStyles); - htmlBuilder.Replace("{{content-placeholder}}", htmlContent); - - var converter = new ConverterProperties(); - var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); - converter.SetTagWorkerFactory(tagWorkerFactory); - - HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter); - - tagWorkerFactory.AddNamedDestinations(); - var pdfOutlines = pdfDocument.GetOutlines(false); - BuildPdfOutlines(pdfOutlines, AllPdfDocumentNodes); - - textDocument.Close(); - pdfStream.Position = 0; - return Task.FromResult(pdfStream); - } - - private void BuildPdfOutlines(PdfOutline parentOutline, List pdfDocumentNodes) - { - foreach (var pdfDocumentNode in pdfDocumentNodes) - { - if (pdfDocumentNode.IgnoreOnOutline) - { - continue; - } - - var outline = parentOutline.AddOutline(pdfDocumentNode.Title); - if (!pdfDocumentNode.Id.IsNullOrWhiteSpace()) - { - outline.AddAction(PdfAction.CreateGoTo(pdfDocumentNode.Id)); - } - - if (pdfDocumentNode.HasChildren) - { - BuildPdfOutlines(outline, pdfDocumentNode.Children); - } - } - } - protected virtual async Task RenderDocumentAsync(PdfDocumentNode pdfDocumentNode) { var renderedDocument = await DocumentSectionRenderer.RenderAsync(pdfDocumentNode.Document.Content, pdfDocumentNode.RenderParameters); @@ -164,7 +134,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator var pdfDocumentNode = new PdfDocumentNode { Title = navigation.Text, - IgnoreOnOutline = navigation.Path == "index.md" + IgnoreOnOutline = navigation.Path == Options.Value.CoverPagePath }; if (!navigation.Path.IsNullOrWhiteSpace()) @@ -228,11 +198,6 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator } } - protected virtual string CalculateDocumentPdfFileName(string projectName, string version, string languageCode) - { - return $"{projectName.ToLower()}-{languageCode.ToLower()}.pdf"; - } - private string NormalizeNavigationPath(string path) { return !path.EndsWith(".md") ? Path.Combine(path, "index.md") : path; @@ -249,12 +214,14 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator { throw new UserFriendlyException($"Cannot validate navigation file '{project.NavigationDocumentName}' for the project {project.Name}."); } - - navigation.Items.Insert(0, new NavigationNode + + if (!Options.Value.CoverPagePath.IsNullOrWhiteSpace()) { - Text = "Index", - Path = "index.md" - }); + navigation.Items.Insert(0, new NavigationNode + { + Path = Options.Value.CoverPagePath + }); + } return navigation; } @@ -337,7 +304,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator private string SetDocumentTitle(string content, string title) { - var titleLine = content.Split('\n').FirstOrDefault(x => x.TrimStart().StartsWith("#")); + var titleLine = content.Split(Environment.NewLine).FirstOrDefault(x => x.TrimStart().StartsWith("#")); if (titleLine == null) { return content; @@ -354,7 +321,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator return title; } - var titleLine = content.Split('\n').FirstOrDefault(x => x.TrimStart().StartsWith("#")); + var titleLine = content.Split(Environment.NewLine).FirstOrDefault(x => x.TrimStart().StartsWith("#")); if (titleLine == null) { return title; @@ -378,8 +345,14 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator private string NormalizeHtmlContent(PdfDocumentNode pdfDocumentNode, string htmlContent) { htmlContent = $"
{htmlContent}
"; - - htmlContent = Regex.Replace(htmlContent, @"(]*)src=""([^""]*)""([^>]*>)", delegate (Match match) + htmlContent = ReplaceRelativeImageUrls(pdfDocumentNode, htmlContent); + + return htmlContent; + } + + private string ReplaceRelativeImageUrls(PdfDocumentNode pdfDocumentNode, string htmlContent) + { + return Regex.Replace(htmlContent, @"(]*)src=""([^""]*)""([^>]*>)", delegate (Match match) { if (IsExternalLink(match.Groups[2].Value)) { @@ -396,8 +369,6 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator return match.Groups[1] + " src=\"" + HttpUtility.HtmlEncode(newImageSource) + "\" " + match.Groups[3]; }, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline); - - return htmlContent; } private bool IsExternalLink(string link) @@ -405,15 +376,4 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator return link.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || link.StartsWith("https://", StringComparison.OrdinalIgnoreCase); } - - protected class PdfDocumentNode - { - public Document Document { get; set; } - public string Title { get; set; } - public string Id { get; set; } - public List Children { get; set; } = []; - public DocumentRenderParameters RenderParameters { get; set; } - public bool HasChildren => Children.Any(); - public bool IgnoreOnOutline { get; set; } - } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfFileStore.cs new file mode 100644 index 0000000000..7cbbc67ee2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfFileStore.cs @@ -0,0 +1,12 @@ +using System.IO; +using System.Threading.Tasks; +using Volo.Docs.Projects; + +namespace Volo.Docs.Documents.Pdf; + +public interface IDocumentPdfFileStore +{ + Task SetAsync(Project project, string version, string languageCode, Stream stream); + + Task GetOrNullAsync(Project project, string version, string languageCode); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/IDocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfGenerator.cs similarity index 57% rename from modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/IDocumentPdfGenerator.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfGenerator.cs index 3fced15bf8..aca44d41be 100644 --- a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/IDocumentPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfGenerator.cs @@ -1,11 +1,10 @@ using System.Threading.Tasks; using Volo.Abp.Content; -using Volo.Abp.DependencyInjection; using Volo.Docs.Projects; -namespace Volo.Docs.Common.Documents; +namespace Volo.Docs.Documents.Pdf; -public interface IDocumentPdfGenerator : ITransientDependency +public interface IDocumentPdfGenerator { Task GenerateAsync(Project project, string version, string languageCode); } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs new file mode 100644 index 0000000000..cb950c8b7b --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace Volo.Docs.Documents.Pdf; + +public interface IPdfRenderer +{ + Task GeneratePdfAsync(string htmlContent, List pdfDocumentNodes); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/HtmlIdTagWorkerFactory.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/HtmlIdTagWorkerFactory.cs similarity index 92% rename from modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/HtmlIdTagWorkerFactory.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/HtmlIdTagWorkerFactory.cs index 02078486e2..4eb9fcda62 100644 --- a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/HtmlIdTagWorkerFactory.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/HtmlIdTagWorkerFactory.cs @@ -5,9 +5,9 @@ using iText.Kernel.Pdf; using iText.Kernel.Pdf.Navigation; using iText.StyledXmlParser.Node; -namespace Volo.Docs.Common.Documents; +namespace Volo.Docs.Documents.Pdf.IText; -public class HtmlIdTagWorkerFactory: DefaultTagWorkerFactory +public class HtmlIdTagWorkerFactory : DefaultTagWorkerFactory { private readonly PdfDocument _pdfDocument; private readonly Dictionary _pageDestinations = new(); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs new file mode 100644 index 0000000000..f4164dfd3a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using iText.Html2pdf; +using iText.Kernel.Pdf; +using iText.Kernel.Pdf.Action; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using ITextDocument = iText.Layout.Document; + +namespace Volo.Docs.Documents.Pdf.IText; + +public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency +{ + protected IOptions Options { get; } + + public ITextPdfRenderer(IOptions options) + { + Options = options; + } + + public virtual Task GeneratePdfAsync(string htmlContent, List pdfDocumentNodes) + { + var pdfStream = new MemoryStream(); + var pdfWrite = new PdfWriter(pdfStream); + var pdfDocument = new PdfDocument(pdfWrite); + var textDocument = new ITextDocument(pdfDocument); + pdfWrite.SetCloseStream(false); + + var htmlBuilder = new StringBuilder(); + htmlBuilder.Append(Options.Value.HtmlLayout); + htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyles); + htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.ContentPlaceholder, htmlContent); + + var converter = new ConverterProperties(); + var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); + converter.SetTagWorkerFactory(tagWorkerFactory); + + HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter); + + tagWorkerFactory.AddNamedDestinations(); + var pdfOutlines = pdfDocument.GetOutlines(false); + BuildPdfOutlines(pdfOutlines, pdfDocumentNodes); + + textDocument.Close(); + pdfStream.Position = 0; + return Task.FromResult(pdfStream); + } + + private void BuildPdfOutlines(PdfOutline parentOutline, List pdfDocumentNodes) + { + foreach (var pdfDocumentNode in pdfDocumentNodes) + { + if (pdfDocumentNode.IgnoreOnOutline) + { + continue; + } + + var outline = parentOutline.AddOutline(pdfDocumentNode.Title); + if (!pdfDocumentNode.Id.IsNullOrWhiteSpace()) + { + outline.AddAction(PdfAction.CreateGoTo(pdfDocumentNode.Id)); + } + + if (pdfDocumentNode.HasChildren) + { + BuildPdfOutlines(outline, pdfDocumentNode.Children); + } + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/PdfDocumentNode.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/PdfDocumentNode.cs new file mode 100644 index 0000000000..1abfc689cc --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/PdfDocumentNode.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using Volo.Docs.Documents.Rendering; + +namespace Volo.Docs.Documents.Pdf; + +public class PdfDocumentNode +{ + public Document Document { get; set; } + public string Title { get; set; } + public string Id { get; set; } + public List Children { get; set; } = []; + public DocumentRenderParameters RenderParameters { get; set; } + public bool HasChildren => Children.Any(); + public bool IgnoreOnOutline { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json b/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json index 13e9ebffb2..717e94c04f 100644 --- a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json +++ b/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json @@ -4,206 +4,95 @@ "rootPath": "docs", "remoteServiceName": "AbpDocs", "controllers": { - "Volo.Docs.Projects.DocsProjectController": { - "controllerName": "DocsProject", - "controllerGroupName": "Project", + "Volo.Docs.Areas.Documents.DocumentNavigationController": { + "controllerName": "DocumentNavigation", + "controllerGroupName": "DocumentNavigation", "isRemoteService": true, "isIntegrationService": false, "apiVersion": null, - "type": "Volo.Docs.Projects.DocsProjectController", - "interfaces": [ - { - "type": "Volo.Docs.Projects.IProjectAppService", - "name": "IProjectAppService", - "methods": [ - { - "name": "GetListAsync", - "parametersOnMethod": [], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - } - }, - { - "name": "GetAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "Volo.Docs.Projects.ProjectDto", - "typeSimple": "Volo.Docs.Projects.ProjectDto" - } - }, - { - "name": "GetVersionsAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - } - }, - { - "name": "GetDefaultLanguageCodeAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - }, - { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "System.String", - "typeSimple": "string" - } - }, - { - "name": "GetLanguageListAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - }, - { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "Volo.Docs.Documents.LanguageConfig", - "typeSimple": "Volo.Docs.Documents.LanguageConfig" - } - } - ] - } - ], + "type": "Volo.Docs.Areas.Documents.DocumentNavigationController", + "interfaces": [], "actions": { - "GetListAsync": { - "uniqueName": "GetListAsync", - "name": "GetListAsync", - "httpMethod": "GET", - "url": "api/docs/projects", - "supportedVersions": [], - "parametersOnMethod": [], - "parameters": [], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - }, - "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetAsyncByShortName": { - "uniqueName": "GetAsyncByShortName", - "name": "GetAsync", + "GetNavigationAsyncByInput": { + "uniqueName": "GetNavigationAsyncByInput", + "name": "GetNavigationAsync", "httpMethod": "GET", - "url": "api/docs/projects/{shortName}", + "url": "docs/document-navigation", "supportedVersions": [], "parametersOnMethod": [ { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", + "name": "input", + "typeAsString": "Volo.Docs.Areas.Models.DocumentNavigation.GetNavigationNodeWithLinkModel, Volo.Docs.Web", + "type": "Volo.Docs.Areas.Models.DocumentNavigation.GetNavigationNodeWithLinkModel", + "typeSimple": "Volo.Docs.Areas.Models.DocumentNavigation.GetNavigationNodeWithLinkModel", "isOptional": false, "defaultValue": null } ], "parameters": [ { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" - } - ], - "returnValue": { - "type": "Volo.Docs.Projects.ProjectDto", - "typeSimple": "Volo.Docs.Projects.ProjectDto" - }, - "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetDefaultLanguageCodeAsyncByShortNameAndVersion": { - "uniqueName": "GetDefaultLanguageCodeAsyncByShortNameAndVersion", - "name": "GetDefaultLanguageCodeAsync", - "httpMethod": "GET", - "url": "api/docs/projects/{shortName}/defaultLanguage", - "supportedVersions": [], - "parametersOnMethod": [ + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, - "defaultValue": null + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", + "nameOnMethod": "input", + "name": "ProjectName", + "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, - "defaultValue": null - } - ], - "parameters": [ + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "ProjectFormat", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "nameOnMethod": "version", - "name": "version", + "nameOnMethod": "input", + "name": "RouteVersion", "jsonName": null, "type": "System.String", "typeSimple": "string", @@ -211,109 +100,99 @@ "defaultValue": null, "constraintTypes": null, "bindingSourceId": "ModelBinding", - "descriptorName": "" + "descriptorName": "input" } ], "returnValue": { - "type": "System.String", - "typeSimple": "string" + "type": "Volo.Docs.Documents.NavigationNode", + "typeSimple": "Volo.Docs.Documents.NavigationNode" }, "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetVersionsAsyncByShortName": { - "uniqueName": "GetVersionsAsyncByShortName", - "name": "GetVersionsAsync", + "implementFrom": "Volo.Docs.Areas.Documents.DocumentNavigationController" + } + } + }, + "Volo.Docs.Areas.Documents.DocumentResourceController": { + "controllerName": "DocumentResource", + "controllerGroupName": "DocumentResource", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Areas.Documents.DocumentResourceController", + "interfaces": [], + "actions": { + "GetResourceByInput": { + "uniqueName": "GetResourceByInput", + "name": "GetResource", "httpMethod": "GET", - "url": "api/docs/projects/{shortName}/versions", + "url": "document-resources", "supportedVersions": [], "parametersOnMethod": [ { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", + "name": "input", + "typeAsString": "Volo.Docs.Documents.GetDocumentResourceInput, Volo.Docs.Application.Contracts", + "type": "Volo.Docs.Documents.GetDocumentResourceInput", + "typeSimple": "Volo.Docs.Documents.GetDocumentResourceInput", "isOptional": false, "defaultValue": null } ], "parameters": [ { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "ProjectId", "jsonName": null, - "type": "System.String", + "type": "System.Guid", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" - } - ], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - }, - "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetLanguageListAsyncByShortNameAndVersion": { - "uniqueName": "GetLanguageListAsyncByShortNameAndVersion", - "name": "GetLanguageListAsync", - "httpMethod": "GET", - "url": "api/docs/projects/{shortName}/{version}/languageList", - "supportedVersions": [], - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", + "nameOnMethod": "input", + "name": "Name", + "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, - "defaultValue": null - } - ], - "parameters": [ + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "Version", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "nameOnMethod": "version", - "name": "version", + "nameOnMethod": "input", + "name": "LanguageCode", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" } ], "returnValue": { - "type": "Volo.Docs.Documents.LanguageConfig", - "typeSimple": "Volo.Docs.Documents.LanguageConfig" + "type": "Microsoft.AspNetCore.Mvc.FileResult", + "typeSimple": "Microsoft.AspNetCore.Mvc.FileResult" }, "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" + "implementFrom": "Volo.Docs.Areas.Documents.DocumentResourceController" } } }, diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs index efe145cac2..dc891f7ca4 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs @@ -1,5 +1,5 @@ +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; -using Volo.Docs.Projects; namespace Volo.Docs.HtmlConverting { diff --git a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs index 55a9eacb37..72d280f300 100644 --- a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs @@ -1,15 +1,11 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Net; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; using Volo.Docs.HtmlConverting; -using Volo.Docs.Pages.Documents.Project; -using Volo.Docs.Projects; using Volo.Docs.Utils; namespace Volo.Docs.Markdown diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs index 59f66f7b82..baa440dccd 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Options; -using Volo.Docs.Projects; +using Volo.Docs.Common.Projects; namespace Volo.Docs.Pages.Documents { 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 fb1f232cb3..366f8d2a82 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 @@ -71,6 +71,7 @@ + @@ -290,6 +291,14 @@ id="sidebar-scroll" class="nav nav-list"> + @if (Model.HasDownloadPdfPermission) + { + + } } diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index c27e0d1f6f..b0c2a0b2c0 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -7,6 +7,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; @@ -15,9 +16,12 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; using Volo.Abp.EventBus.Local; +using Volo.Docs.Common; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; using Volo.Docs.Documents.Rendering; using Volo.Docs.HtmlConverting; @@ -90,6 +94,8 @@ namespace Volo.Docs.Pages.Documents.Project public bool FullSearchEnabled { get; set; } public bool IsLatestVersion { get; private set; } + + public bool HasDownloadPdfPermission { get; set; } public DocumentNavigationsDto DocumentNavigationsDto { get; private set; } @@ -99,6 +105,7 @@ namespace Volo.Docs.Pages.Documents.Project private readonly IProjectAppService _projectAppService; private readonly IWebDocumentSectionRenderer _webDocumentSectionRenderer; private readonly DocsUiOptions _uiOptions; + private readonly IPermissionChecker _permissionChecker; protected IDocsLinkGenerator DocsLinkGenerator => LazyServiceProvider.LazyGetRequiredService(); @@ -109,7 +116,8 @@ namespace Volo.Docs.Pages.Documents.Project IDocumentToHtmlConverterFactory documentToHtmlConverterFactory, IProjectAppService projectAppService, IOptions options, - IWebDocumentSectionRenderer webDocumentSectionRenderer) + IWebDocumentSectionRenderer webDocumentSectionRenderer, + IPermissionChecker permissionChecker) { ObjectMapperContext = typeof(DocsWebModule); @@ -117,6 +125,7 @@ namespace Volo.Docs.Pages.Documents.Project _documentToHtmlConverterFactory = documentToHtmlConverterFactory; _projectAppService = projectAppService; _webDocumentSectionRenderer = webDocumentSectionRenderer; + _permissionChecker = permissionChecker; _uiOptions = options.Value; LocalizationResourceType = typeof(DocsResource); @@ -136,7 +145,7 @@ namespace Volo.Docs.Pages.Documents.Project { return RedirectPermanent(redirectUrl); } - + return await SetPageAsync(); } @@ -146,7 +155,7 @@ namespace Volo.Docs.Pages.Documents.Project ShowProjectsCombobox = _uiOptions.ShowProjectsCombobox && !_uiOptions.SingleProjectMode.Enable; ShowProjectsComboboxLabel = ShowProjectsCombobox && _uiOptions.ShowProjectsComboboxLabel; FullSearchEnabled = await _documentAppService.FullSearchEnabledAsync(); - + HasDownloadPdfPermission = await _permissionChecker.IsGrantedAsync(DocsCommonPermissions.Documents.PdfGeneration); try { await SetProjectAsync(); diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css index e8d0a035a0..dc720fba6d 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css @@ -45,4 +45,18 @@ body { outline: none; } +.docs-sidebar-footer { + border-block-start: 1px solid #aaa; + border-block-end: 1px solid #aaa; +} + +.download-pdf-btn { + text-align: left; + width: 100%; + color: #aaa; + background-color: #0000; + border-color:#0000; + font-size: 14px; +} + /*# sourceMappingURL=Index.css.map */ diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss index 426dec284c..9589b1fb73 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss @@ -6,9 +6,9 @@ } } -.input-group{ - .input-group-text{ - background-color: transparent!important; +.input-group { + .input-group-text { + background-color: transparent !important; } } @@ -16,10 +16,12 @@ .next-link, .prev-link { .desc { color: #0D6EFD; - .fa{ + + .fa { font-size: 12px; } } + .title { font-weight: 600; font-size: 18px; @@ -27,3 +29,46 @@ } } } + +body { + top: 0px !important; +} + +.skiptranslate { + iframe { + display: none !important; + } +} + +.google_translate_text { + color: #aaa; + font-family: var(--bs-body-font-family); + font-size: 10pt; + margin-left: 2px; + font-weight: 500; +} + +.goog-te-gadget { + white-space: break-spaces !important; +} + +.goog-te-combo { + &:focus-visible { + border: 0px; + outline: none; + } +} + +.docs-sidebar-footer { + border-block-start: 1px solid #aaa; + border-block-end: 1px solid #aaa; +} + +.download-pdf-btn { + text-align: left; + width: 100%; + color: #aaa; + background-color: transparent; + border-color: transparent; + font-size: 14px; +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs index 7be35394ae..ad60019b57 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs @@ -3,18 +3,15 @@ using System.Collections.Generic; using System.Linq; using System.Text.Encodings.Web; using System.Threading.Tasks; -using System.Web; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; using Volo.Abp.Data; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; using Volo.Docs.GitHub.Documents.Version; -using Volo.Docs.HtmlConverting; -using Volo.Docs.Models; using Volo.Docs.Projects; -using Volo.Docs.Utils; namespace Volo.Docs.Pages.Documents { diff --git a/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-common-proxy.js b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-common-proxy.js new file mode 100644 index 0000000000..014e357cba --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-common-proxy.js @@ -0,0 +1,68 @@ +/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */ + + +// module docs-common + +(function(){ + + // controller volo.docs.documents.docsDocumentPdfGenerator + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.documents.docsDocumentPdfGenerator'); + + volo.docs.documents.docsDocumentPdfGenerator.generatePdf = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + })(); + + // controller volo.docs.projects.docsProject + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.projects.docsProject'); + + volo.docs.projects.docsProject.getList = function(ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.get = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getDefaultLanguageCode = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/defaultLanguage' + abp.utils.buildQueryString([{ name: 'version', value: version }]) + '', + type: 'GET' + }, { dataType: 'text' }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getVersions = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/versions', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getLanguageList = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/' + version + '/languageList', + type: 'GET' + }, ajaxParams)); + }; + + })(); + +})(); + + diff --git a/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js index 3195d15cd6..32bcf101cb 100644 --- a/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js +++ b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js @@ -5,43 +5,30 @@ (function(){ - // controller volo.docs.projects.docsProject + // controller volo.docs.areas.documents.documentNavigation (function(){ - abp.utils.createNamespace(window, 'volo.docs.projects.docsProject'); + abp.utils.createNamespace(window, 'volo.docs.areas.documents.documentNavigation'); - volo.docs.projects.docsProject.getList = function(ajaxParams) { + volo.docs.areas.documents.documentNavigation.getNavigation = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects', + url: abp.appPath + 'docs/document-navigation' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }, { name: 'projectName', value: input.projectName }, { name: 'projectFormat', value: input.projectFormat }, { name: 'routeVersion', value: input.routeVersion }]) + '', type: 'GET' }, ajaxParams)); }; - volo.docs.projects.docsProject.get = function(shortName, ajaxParams) { - return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '', - type: 'GET' - }, ajaxParams)); - }; + })(); - volo.docs.projects.docsProject.getDefaultLanguageCode = function(shortName, version, ajaxParams) { - return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '/defaultLanguage' + abp.utils.buildQueryString([{ name: 'version', value: version }]) + '', - type: 'GET' - }, { dataType: 'text' }, ajaxParams)); - }; + // controller volo.docs.areas.documents.documentResource - volo.docs.projects.docsProject.getVersions = function(shortName, ajaxParams) { - return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '/versions', - type: 'GET' - }, ajaxParams)); - }; + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.areas.documents.documentResource'); - volo.docs.projects.docsProject.getLanguageList = function(shortName, version, ajaxParams) { + volo.docs.areas.documents.documentResource.getResource = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '/' + version + '/languageList', + url: abp.appPath + 'document-resources' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'name', value: input.name }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', type: 'GET' }, ajaxParams)); }; diff --git a/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs b/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs index 8f92c414c1..662db4c6aa 100644 --- a/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs +++ b/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; using Shouldly; -using Volo.Docs.Projects; +using Volo.Docs.Common.Projects; using Xunit; namespace Volo.Docs From cfc29a88621ffbfa1624448ffc8ebeea626b31d1 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 21 Apr 2025 13:53:50 +0800 Subject: [PATCH 04/19] Add localization texts --- .../Resources/Docs/ApplicationContracts/ar.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/cs.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/de-DE.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/de.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/el.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/en-GB.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/en.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/es.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/fi.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/fr.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/hi.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/hr.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/hu.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/is.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/it.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/nl.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/pl-PL.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/pt-BR.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/ro-RO.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/ru.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/sk.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/sl.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/sv.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/tr.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/vi.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/zh-Hans.json | 8 +++++++- .../Resources/Docs/ApplicationContracts/zh-Hant.json | 10 ++++++++-- .../Common/DocsCommonApplicationContractsModule.cs | 2 +- .../Resources/Docs/ApplicationContracts/ar.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/cs.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/de-DE.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/de.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/el.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/en-GB.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/en.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/es.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/fi.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/fr.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/hi.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/hr.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/hu.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/is.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/it.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/nl.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/pl-PL.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/pt-BR.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/ro-RO.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/ru.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/sk.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/sl.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/sv.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/tr.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/vi.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/zh-Hans.json | 7 +++++++ .../Resources/Docs/ApplicationContracts/zh-Hant.json | 7 +++++++ .../Volo/Docs/Localization/Domain/ar.json | 3 ++- .../Volo/Docs/Localization/Domain/cs.json | 3 ++- .../Volo/Docs/Localization/Domain/de.json | 3 ++- .../Volo/Docs/Localization/Domain/el.json | 3 ++- .../Volo/Docs/Localization/Domain/en-GB.json | 3 ++- .../Volo/Docs/Localization/Domain/en.json | 3 ++- .../Volo/Docs/Localization/Domain/es.json | 3 ++- .../Volo/Docs/Localization/Domain/fi.json | 3 ++- .../Volo/Docs/Localization/Domain/fr.json | 3 ++- .../Volo/Docs/Localization/Domain/hi.json | 3 ++- .../Volo/Docs/Localization/Domain/hr.json | 3 ++- .../Volo/Docs/Localization/Domain/hu.json | 3 ++- .../Volo/Docs/Localization/Domain/is.json | 3 ++- .../Volo/Docs/Localization/Domain/it.json | 3 ++- .../Volo/Docs/Localization/Domain/nl.json | 3 ++- .../Volo/Docs/Localization/Domain/pl-PL.json | 3 ++- .../Volo/Docs/Localization/Domain/pt-BR.json | 3 ++- .../Volo/Docs/Localization/Domain/ro-RO.json | 3 ++- .../Volo/Docs/Localization/Domain/ru.json | 3 ++- .../Volo/Docs/Localization/Domain/sk.json | 3 ++- .../Volo/Docs/Localization/Domain/sl.json | 3 ++- .../Volo/Docs/Localization/Domain/sv.json | 3 ++- .../Volo/Docs/Localization/Domain/tr.json | 3 ++- .../Volo/Docs/Localization/Domain/vi.json | 3 ++- .../Volo/Docs/Localization/Domain/zh-Hans.json | 3 ++- .../Volo/Docs/Localization/Domain/zh-Hant.json | 3 ++- 81 files changed, 432 insertions(+), 55 deletions(-) create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ar.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/cs.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de-DE.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/el.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en-GB.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/es.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fi.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fr.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hi.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hr.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hu.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/is.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/it.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/nl.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pl-PL.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pt-BR.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ro-RO.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ru.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sk.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sl.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sv.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/vi.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json create mode 100644 modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json index 458d1592f0..15cfaaa9d7 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json @@ -57,6 +57,12 @@ "LastCachedTime": "وقت ذاكرة التخزين", "Project": "مشروع ", "AdvancedFilters": "مرشحات متقدمة", - "RemoveCacheAndReIndexConfirmation": "ستتم إزالة المستند \"{0}\" من ذاكرة التخزين المؤقت وإعادة فهرسته. هل تؤكد؟" + "RemoveCacheAndReIndexConfirmation": "ستتم إزالة المستند \"{0}\" من ذاكرة التخزين المؤقت وإعادة فهرسته. هل تؤكد؟", + "GeneratePdf": "توليد PDF", + "Generating": "يتم توليد...", + "Language": "اللغة", + "ForceToGenerateNewPdf": "قوة لتوليد PDF جديد", + "PdfGeneratedSuccessfully": "تم توليد PDF بنجاح", + "GenerateAndDownloadPdf": "توليد وتحميل PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json index ff6c135a90..63fc1344e0 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json @@ -57,6 +57,12 @@ "LastCachedTime": "Čas uložení v mezipaměti", "Project": "Projekt", "AdvancedFilters": "Pokročilé filtry", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bude odstraněn z mezipaměti a znovu zaindexován. Potvrzujete to?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bude odstraněn z mezipaměti a znovu zaindexován. Potvrzujete to?", + "GeneratePdf": "Generovat PDF", + "Generating": "Generování...", + "Language": "Jazyk", + "ForceToGenerateNewPdf": "Vynutit generování nového PDF", + "PdfGeneratedSuccessfully": "PDF generován úspěšně", + "GenerateAndDownloadPdf": "Generovat a stáhnout PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json index ce7c8cafb0..907fc8236b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json @@ -56,6 +56,12 @@ "FileName": "Dateiname", "LastCachedTime": "Cache-Zeit", "Project": "Projekt", - "RemoveCacheAndReIndexConfirmation": "Das Dokument \"{0}\" wird aus dem Cache entfernt und neu indiziert. Können Sie das bestätigen?" + "RemoveCacheAndReIndexConfirmation": "Das Dokument \"{0}\" wird aus dem Cache entfernt und neu indiziert. Können Sie das bestätigen?", + "GeneratePdf": "PDF generieren", + "Generating": "Generieren...", + "Language": "Sprache", + "ForceToGenerateNewPdf": "Neues PDF erzwingen", + "PdfGeneratedSuccessfully": "PDF erfolgreich generiert", + "GenerateAndDownloadPdf": "PDF generieren und herunterladen" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json index 0fd1c535b2..7ec5d5122b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json @@ -57,6 +57,12 @@ "LastCachedTime": "Zwischenspeicher", "Project": "Projekt", "AdvancedFilters": "Erweiterte Filter", - "RemoveCacheAndReIndexConfirmation": "Das Dokument „{0}“ wird aus dem Cache entfernt und neu indiziert. Bestätigen Sie?" + "RemoveCacheAndReIndexConfirmation": "Das Dokument „{0}“ wird aus dem Cache entfernt und neu indiziert. Bestätigen Sie?", + "GeneratePdf": "PDF generieren", + "Generating": "Generieren...", + "Language": "Sprache", + "ForceToGenerateNewPdf": "Neues PDF erzwingen", + "PdfGeneratedSuccessfully": "PDF erfolgreich generiert", + "GenerateAndDownloadPdf": "PDF generieren und herunterladen" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json index c2a3f69a53..75d9bb8122 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json @@ -56,6 +56,12 @@ "FileName": "Όνομα αρχείου", "LastCachedTime": "Χρόνος προσωρινής αποθήκευσης", "Project": "Εργο", - "RemoveCacheAndReIndexConfirmation": "Το έγγραφο \"{0}\" θα αφαιρεθεί από την προσωρινή μνήμη και θα αναπροσαρμοστεί εκ νέου. Επιβεβαιώνετε;" + "RemoveCacheAndReIndexConfirmation": "Το έγγραφο \"{0}\" θα αφαιρεθεί από την προσωρινή μνήμη και θα αναπροσαρμοστεί εκ νέου. Επιβεβαιώνετε;", + "GeneratePdf": "Δημιουργία PDF", + "Generating": "Δημιουργία...", + "Language": "Γλώσσα", + "ForceToGenerateNewPdf": "Βάλτε το νέο PDF", + "PdfGeneratedSuccessfully": "Το PDF αναπροσαρμοστεί εκ νέου", + "GenerateAndDownloadPdf": "Δημιουργία και λήψη PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json index d72c523ef5..de69b69e16 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json @@ -56,6 +56,12 @@ "FileName": "File name", "LastCachedTime": "Cache time", "Project": "Project", - "AdvancedFilters": "Advanced Filters" + "AdvancedFilters": "Advanced Filters", + "GeneratePdf": "Generate PDF", + "Generating": "Generating...", + "Language": "Language", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json index 5302cdcffb..a0dee2cdd1 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json @@ -57,6 +57,12 @@ "LastCachedTime": "Cache time", "Project": "Project", "AdvancedFilters": "Advanced Filters", - "RemoveCacheAndReIndexConfirmation": "The document \"{0}\" will be removed from the cache and re-indexed. Do you confirm?" + "RemoveCacheAndReIndexConfirmation": "The document \"{0}\" will be removed from the cache and re-indexed. Do you confirm?", + "GeneratePdf": "Generate PDF", + "Generating": "Generating...", + "Language": "Language", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json index 911fe2745a..9530f8504c 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json @@ -57,6 +57,12 @@ "LastCachedTime": "Última actualización de caché", "Project": "Proyecto", "AdvancedFilters": "Filtros avanzados", - "RemoveCacheAndReIndexConfirmation": "El documento \"{0}\" será eliminado de la caché y reindexado. ¿Lo confirma?" + "RemoveCacheAndReIndexConfirmation": "El documento \"{0}\" será eliminado de la caché y reindexado. ¿Lo confirma?", + "GeneratePdf": "Generar PDF", + "Generating": "Generando...", + "Language": "Idioma", + "ForceToGenerateNewPdf": "Forzar a generar un nuevo PDF", + "PdfGeneratedSuccessfully": "PDF generado correctamente", + "GenerateAndDownloadPdf": "Generar y descargar PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json index e3e826c1b7..c1122140c2 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json @@ -57,6 +57,12 @@ "LastCachedTime": "Välimuistin aika", "Project": "Projekti", "AdvancedFilters": "Edistyneet suodattimet", - "RemoveCacheAndReIndexConfirmation": "Dokumentti \"{0}\" poistetaan välimuistista ja indeksoidaan uudelleen. Vahvistatko?" + "RemoveCacheAndReIndexConfirmation": "Dokumentti \"{0}\" poistetaan välimuistista ja indeksoidaan uudelleen. Vahvistatko?", + "GeneratePdf": "Generoi PDF", + "Generating": "Generoiminen...", + "Language": "Kieli", + "ForceToGenerateNewPdf": "Vahvista uusi PDF", + "PdfGeneratedSuccessfully": "PDF generoidaan onnistuneesti", + "GenerateAndDownloadPdf": "Generoi ja lataa PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json index b2fdef8201..98207b1a6a 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json @@ -57,6 +57,12 @@ "LastCachedTime": "Temps de cache", "Project": "Projet", "AdvancedFilters": "Filtres avancés", - "RemoveCacheAndReIndexConfirmation": "Le document \"{0}\" sera supprimé du cache et réindexé. Confirmez-vous ?" + "RemoveCacheAndReIndexConfirmation": "Le document \"{0}\" sera supprimé du cache et réindexé. Confirmez-vous ?", + "GeneratePdf": "Générer PDF", + "Generating": "Génération...", + "Language": "Langue", + "ForceToGenerateNewPdf": "Forcer à générer un nouveau PDF", + "PdfGeneratedSuccessfully": "PDF généré avec succès", + "GenerateAndDownloadPdf": "Générer et télécharger PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json index adad5e064f..d55ba7fb9b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json @@ -57,6 +57,12 @@ "LastCachedTime": "कैश समय", "Project": "परियोजना", "AdvancedFilters": "उन्नत फ़िल्टर", - "RemoveCacheAndReIndexConfirmation": "दस्u200Dतावेज़ \"{0}\" को संचय से हटा दिया जाएगा और पुन: अनुक्रमित किया जाएगा। क्या आप पुष्टि करते हैं?" + "RemoveCacheAndReIndexConfirmation": "दस्तावेज़ \"{0}\" को संचय से हटा दिया जाएगा और पुन: अनुक्रमित किया जाएगा। क्या आप पुष्टि करते हैं?", + "GeneratePdf": "PDF उत्पन्न करें", + "Generating": "उत्पन्न कर रहा है...", + "Language": "भाषा", + "ForceToGenerateNewPdf": "नया PDF उत्पन्न करें", + "PdfGeneratedSuccessfully": "PDF सफलतापूर्वक उत्पन्न हो गया", + "GenerateAndDownloadPdf": "PDF उत्पन्न और डाउनलोड करें" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json index cf0a31368f..6890839ee2 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json @@ -57,6 +57,12 @@ "LastCachedTime": "Vrijeme predmemorije", "Project": "Projekt", "AdvancedFilters": "Napredni filtri", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bit će uklonjen iz predmemorije i ponovno indeksiran. Potvrđujete li?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bit će uklonjen iz predmemorije i ponovno indeksiran. Potvrđujete li?", + "GeneratePdf": "Generiraj PDF", + "Generating": "Generiranje...", + "Language": "Jezik", + "ForceToGenerateNewPdf": "Prisili generiranje novog PDF-a", + "PdfGeneratedSuccessfully": "PDF generiran uspješno", + "GenerateAndDownloadPdf": "Generiraj i preuzmi PDF" } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json index 587f67e72c..15a51e404d 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json @@ -58,6 +58,12 @@ "LastCachedTime": "Cache idő", "Project": "Projekt", "AdvancedFilters": "Speciális szűrők", - "RemoveCacheAndReIndexConfirmation": "A \"{0}\" dokumentumot eltávolítjuk a gyorsítótárból és újraindexeljük. Megerősíti?" + "RemoveCacheAndReIndexConfirmation": "A \"{0}\" dokumentumot eltávolítjuk a gyorsítótárból és újraindexeljük. Megerősíti?", + "GeneratePdf": "PDF generálása", + "Generating": "Generálás...", + "Language": "Nyelv", + "ForceToGenerateNewPdf": "Új PDF generálása", + "PdfGeneratedSuccessfully": "PDF generálás sikeres", + "GenerateAndDownloadPdf": "Generálás és letöltés PDF-ben" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json index c3e8fa957b..aed161fa90 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json @@ -57,6 +57,12 @@ "LastCachedTime": "Tími geymt í skyndiminni", "Project": "Verkefni", "AdvancedFilters": "Ítarlegar síur", - "RemoveCacheAndReIndexConfirmation": "Skjalið \"{0}\" verður fjarlægt úr skyndiminni og endurtryggt. Staðfestir þú?" + "RemoveCacheAndReIndexConfirmation": "Skjalið \"{0}\" verður fjarlægt úr skyndiminni og endurtryggt. Staðfestir þú?", + "GeneratePdf": "Generate PDF", + "Generating": "Generating...", + "Language": "Language", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json index 40f94e8077..8b5aaf071e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json @@ -57,6 +57,12 @@ "LastCachedTime": "Tempo di cache", "Project": "Progetto", "AdvancedFilters": "Filtri avanzati", - "RemoveCacheAndReIndexConfirmation": "Il documento \"{0}\" verrà rimosso dalla cache e reindicizzato. Confermate?" + "RemoveCacheAndReIndexConfirmation": "Il documento \"{0}\" verrà rimosso dalla cache e reindicizzato. Confermate?", + "GeneratePdf": "Genera PDF", + "Generating": "Generazione...", + "Language": "Lingua", + "ForceToGenerateNewPdf": "Forza a generare un nuovo PDF", + "PdfGeneratedSuccessfully": "PDF generato con successo", + "GenerateAndDownloadPdf": "Genera e scarica PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json index 201d7c5da0..8ce0777171 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json @@ -57,6 +57,12 @@ "LastCachedTime": "Cache tijd", "Project": "Project", "AdvancedFilters": "Geavanceerde filters", - "RemoveCacheAndReIndexConfirmation": "Het document \"{0}\" wordt uit de cache verwijderd en opnieuw geïndexeerd. Bevestigt u?" + "RemoveCacheAndReIndexConfirmation": "Het document \"{0}\" wordt uit de cache verwijderd en opnieuw geïndexeerd. Bevestigt u?", + "GeneratePdf": "PDF genereren", + "Generating": "Genereren...", + "Language": "Taal", + "ForceToGenerateNewPdf": "Forceer nieuwe PDF te genereren", + "PdfGeneratedSuccessfully": "PDF succesvol gegenereerd", + "GenerateAndDownloadPdf": "PDF genereren en downloaden" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json index ec9de0de07..785588c3fe 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json @@ -57,6 +57,12 @@ "LastCachedTime": "Czas w pamięci podręcznej", "Project": "Projekt", "AdvancedFilters": "Zaawansowane filtry", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" zostanie usunięty z pamięci podręcznej i ponownie zaindeksowany. Czy potwierdzasz?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" zostanie usunięty z pamięci podręcznej i ponownie zaindeksowany. Czy potwierdzasz?", + "GeneratePdf": "Generuj PDF", + "Generating": "Generowanie...", + "Language": "Język", + "ForceToGenerateNewPdf": "Wymuś generowanie nowego PDF", + "PdfGeneratedSuccessfully": "PDF został pomyślnie wygenerowany", + "GenerateAndDownloadPdf": "Generuj i pobierz PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json index b34ab4b9ef..59f5006b76 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json @@ -57,6 +57,12 @@ "LastCachedTime": "Tempo de cache", "Project": "Projeto", "AdvancedFilters": "Filtros Avançados", - "RemoveCacheAndReIndexConfirmation": "O documento \"{0}\" será removido do cache e indexado novamente. Você confirma?" + "RemoveCacheAndReIndexConfirmation": "O documento \"{0}\" será removido do cache e indexado novamente. Você confirma?", + "GeneratePdf": "Gerar PDF", + "Generating": "Gerando...", + "Language": "Idioma", + "ForceToGenerateNewPdf": "Forçar para gerar um novo PDF", + "PdfGeneratedSuccessfully": "PDF gerado com sucesso", + "GenerateAndDownloadPdf": "Gerar e baixar PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json index f055110a2f..315b220454 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json @@ -57,6 +57,12 @@ "LastCachedTime": "Durată cache", "Project": "Proiect", "AdvancedFilters": "Filtre avansate", - "RemoveCacheAndReIndexConfirmation": "Documentul \"{0}\" va fi eliminat din memoria cache și va fi reindexat. Confirmați?" + "RemoveCacheAndReIndexConfirmation": "Documentul \"{0}\" va fi eliminat din memoria cache și va fi reindexat. Confirmați?", + "GeneratePdf": "Generare PDF", + "Generating": "Generare...", + "Language": "Limba", + "ForceToGenerateNewPdf": "Forțați generarea unui nou PDF", + "PdfGeneratedSuccessfully": "PDF generat cu succes", + "GenerateAndDownloadPdf": "Generare și descărcare PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json index 5f9836d957..59ad3ad1cc 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json @@ -57,6 +57,12 @@ "LastCachedTime": "Время кеширования", "Project": "Проект", "AdvancedFilters": "Расширенные фильтры", - "RemoveCacheAndReIndexConfirmation": "Документ \"{0}\" будет удален из кэша и переиндексирован. Вы подтверждаете?" + "RemoveCacheAndReIndexConfirmation": "Документ \"{0}\" будет удален из кэша и переиндексирован. Вы подтверждаете?", + "GeneratePdf": "Генерировать PDF", + "Generating": "Генерация...", + "Language": "Язык", + "ForceToGenerateNewPdf": "Принудительное создание нового PDF", + "PdfGeneratedSuccessfully": "PDF успешно сгенерирован", + "GenerateAndDownloadPdf": "Сгенерировать и скачать PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json index 53578e22dd..62e57ccc4c 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json @@ -57,6 +57,12 @@ "LastCachedTime": "Čas vyrovnávacej pamäte", "Project": "Projekt", "AdvancedFilters": "Pokročilé filtre", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" sa odstráni z vyrovnávacej pamäte a znovu sa zaindexuje. Potvrdzujete?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" sa odstráni z vyrovnávacej pamäte a znovu sa zaindexuje. Potvrdzujete?", + "GeneratePdf": "Generovať PDF", + "Generating": "Generovanie...", + "Language": "Jazyk", + "ForceToGenerateNewPdf": "Vynútiť generovanie nového PDF", + "PdfGeneratedSuccessfully": "PDF generovaný úspešne", + "GenerateAndDownloadPdf": "Generovať a stiahnuť PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json index 3bcfcd4e85..904df440bd 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json @@ -57,6 +57,12 @@ "LastCachedTime": "Čas pred pomnilnika", "Project": "Projekt", "AdvancedFilters": "Napredni filtri", - "RemoveCacheAndReIndexConfirmation": "Dokument »{0}« bo odstranjen iz predpomnilnika in ponovno indeksiran. Ali potrjuješ?" + "RemoveCacheAndReIndexConfirmation": "Dokument »{0}« bo odstranjen iz predpomnilnika in ponovno indeksiran. Ali potrjuješ?", + "GeneratePdf": "Generiraj PDF", + "Generating": "Generiranje...", + "Language": "Jezik", + "ForceToGenerateNewPdf": "Prisili generiranje novega PDF", + "PdfGeneratedSuccessfully": "PDF generiran uspešno", + "GenerateAndDownloadPdf": "Generiraj in prenesi PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json index cbde97c756..694fb74c9c 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json @@ -57,6 +57,12 @@ "LastCachedTime": "Cache-tid", "Project": "Projekt", "AdvancedFilters": "Avancerade filter", - "RemoveCacheAndReIndexConfirmation": "Dokumentet \"{0}\" kommer att tas bort från cacheminnet och indexeras på nytt. Kan du bekräfta detta?" + "RemoveCacheAndReIndexConfirmation": "Dokumentet \"{0}\" kommer att tas bort från cacheminnet och indexeras på nytt. Kan du bekräfta detta?", + "GeneratePdf": "Generera PDF", + "Generating": "Genererar...", + "Language": "Språk", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json index ab600c1db5..aece0ba3e8 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json @@ -57,6 +57,12 @@ "LastCachedTime": "Önbellek süresi", "Project": "Proje", "AdvancedFilters": "Gelişmiş Filtre", - "RemoveCacheAndReIndexConfirmation": "\"{0}\" belgesi önbellekten kaldırılacak ve yeniden indekslenecektir. Onaylıyor musunuz?" + "RemoveCacheAndReIndexConfirmation": "\"{0}\" belgesi önbellekten kaldırılacak ve yeniden indekslenecektir. Onaylıyor musunuz?", + "GeneratePdf": "PDF oluştur", + "Generating": "Oluşturuluyor...", + "Language": "Dil", + "ForceToGenerateNewPdf": "Yeni bir PDF oluştur", + "PdfGeneratedSuccessfully": "PDF başarıyla oluşturuldu", + "GenerateAndDownloadPdf": "PDF oluştur ve indir" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json index 9b47a049a9..b6e68b8bf6 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json @@ -57,6 +57,12 @@ "LastCachedTime": "Thời gian lưu vào bộ nhớ đệm", "Project": "Dự án", "AdvancedFilters": "Bộ lọc nâng cao", - "RemoveCacheAndReIndexConfirmation": "Tài liệu "{0}" sẽ bị xóa khỏi bộ đệm và được lập chỉ mục lại. Bạn có xác nhận không?" + "RemoveCacheAndReIndexConfirmation": "Tài liệu "{0}" sẽ bị xóa khỏi bộ đệm và được lập chỉ mục lại. Bạn có xác nhận không?", + "GeneratePdf": "Tạo PDF", + "Generating": "Đang tạo...", + "Language": "Ngôn ngữ", + "ForceToGenerateNewPdf": "Tạo PDF mới", + "PdfGeneratedSuccessfully": "PDF đã được tạo thành công", + "GenerateAndDownloadPdf": "Tạo và tải xuống PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json index e5bb9f15b6..d2273412ad 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json @@ -57,6 +57,12 @@ "LastCachedTime": "缓存项", "Project": "项目", "AdvancedFilters": "高级过滤器", - "RemoveCacheAndReIndexConfirmation": "文档“{0}”将从缓存中删除并重新编制索引。 你确认吗?" + "RemoveCacheAndReIndexConfirmation": "文档“{0}”将从缓存中删除并重新编制索引。 你确认吗?", + "GeneratePdf": "生成PDF", + "Generating": "生成中...", + "Language": "语言", + "ForceToGenerateNewPdf": "强制生成新PDF", + "PdfGeneratedSuccessfully": "PDF生成成功", + "GenerateAndDownloadPdf": "生成并下载PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json index c246a74646..7492a2c462 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json @@ -55,8 +55,14 @@ "LanguageCode": "語言代碼", "FileName": "文檔名稱", "LastCachedTime": "緩存時間", - "Project": "项目", + "Project": "專案", "AdvancedFilters": "進階過濾器", - "RemoveCacheAndReIndexConfirmation": "文檔“{0}”將從緩存中刪除並重新編制索引。 你確認嗎?" + "RemoveCacheAndReIndexConfirmation": "文檔“{0}”將從緩存中刪除並重新編制索引。 你確認嗎?", + "GeneratePdf": "生成PDF", + "Generating": "生成中...", + "Language": "語言", + "ForceToGenerateNewPdf": "强制生成新PDF", + "PdfGeneratedSuccessfully": "PDF生成成功", + "GenerateAndDownloadPdf": "生成并下载PDF" } } \ No newline at end of file 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 index bc2741fd41..8e11262d3d 100644 --- 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 @@ -25,7 +25,7 @@ public class DocsCommonApplicationContractsModule : AbpModule { options.Resources .Get() - .AddVirtualJson("Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts"); + .AddVirtualJson("Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts"); }); } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ar.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ar.json new file mode 100644 index 0000000000..ff14b26dc6 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ar.json @@ -0,0 +1,7 @@ +{ + "culture": "ar", + "texts": { + "Permission:DocumentManagement.Common": "إدارة المستندات العامة", + "Permission:PdfGeneration": "إنشاء ملفات PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/cs.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/cs.json new file mode 100644 index 0000000000..7999e95a27 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/cs.json @@ -0,0 +1,7 @@ +{ + "culture": "cs", + "texts": { + "Permission:DocumentManagement.Common": "Správa dokumentů", + "Permission:PdfGeneration": "Generování PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de-DE.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de-DE.json new file mode 100644 index 0000000000..0b2c842bb3 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de-DE.json @@ -0,0 +1,7 @@ +{ + "culture": "de-DE", + "texts": { + "Permission:DocumentManagement.Common": "Dokumentenverwaltung", + "Permission:PdfGeneration": "PDF-Generierung" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de.json new file mode 100644 index 0000000000..95d2923d1e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de.json @@ -0,0 +1,7 @@ +{ + "culture": "de", + "texts": { + "Permission:DocumentManagement.Common": "Dokumentenverwaltung", + "Permission:PdfGeneration": "PDF-Generierung" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/el.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/el.json new file mode 100644 index 0000000000..3200537f6d --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/el.json @@ -0,0 +1,7 @@ +{ + "culture": "el", + "texts": { + "Permission:DocumentManagement.Common": "Διαχείριση Εγγράφων", + "Permission:PdfGeneration": "Δημιουργία PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en-GB.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en-GB.json new file mode 100644 index 0000000000..8f01efadbf --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en-GB.json @@ -0,0 +1,7 @@ +{ + "culture": "en-GB", + "texts": { + "Permission:DocumentManagement.Common": "Document Management Common", + "Permission:PdfGeneration": "PDF Generation" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en.json new file mode 100644 index 0000000000..3901eb8d1c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en.json @@ -0,0 +1,7 @@ +{ + "culture": "en", + "texts": { + "Permission:DocumentManagement.Common": "Document Management Common", + "Permission:PdfGeneration": "PDF Generation" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/es.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/es.json new file mode 100644 index 0000000000..707bd71c72 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/es.json @@ -0,0 +1,7 @@ +{ + "culture": "es", + "texts": { + "Permission:DocumentManagement.Common": "Gestión de documentos comunes", + "Permission:PdfGeneration": "Generación de PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fi.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fi.json new file mode 100644 index 0000000000..7e3a84ff00 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fi.json @@ -0,0 +1,7 @@ +{ + "culture": "fi", + "texts": { + "Permission:DocumentManagement.Common": "Tiedostonhallinta", + "Permission:PdfGeneration": "PDF-generointi" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fr.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fr.json new file mode 100644 index 0000000000..6eba3e78c1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fr.json @@ -0,0 +1,7 @@ +{ + "culture": "fr", + "texts": { + "Permission:DocumentManagement.Common": "Gestion des documents communs", + "Permission:PdfGeneration": "Génération de PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hi.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hi.json new file mode 100644 index 0000000000..5208d04868 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hi.json @@ -0,0 +1,7 @@ +{ + "culture": "hi", + "texts": { + "Permission:DocumentManagement.Common": "सामान्य दस्तावेज़ प्रबंधन", + "Permission:PdfGeneration": "PDF उत्पन्न करना" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hr.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hr.json new file mode 100644 index 0000000000..8da0d89a98 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hr.json @@ -0,0 +1,7 @@ +{ + "culture": "hr", + "texts": { + "Permission:DocumentManagement.Common": "Upravljanje zajedničkih dokumenata", + "Permission:PdfGeneration": "Generiranje PDF-a" + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hu.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hu.json new file mode 100644 index 0000000000..30a2bd39f8 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hu.json @@ -0,0 +1,7 @@ +{ + "culture": "hu", + "texts": { + "Permission:DocumentManagement.Common": "Általános dokumentumkezelés", + "Permission:PdfGeneration": "PDF generálás" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/is.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/is.json new file mode 100644 index 0000000000..9e0f6b19c9 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/is.json @@ -0,0 +1,7 @@ +{ + "culture": "is", + "texts": { + "Permission:DocumentManagement.Common": "Almennir skjöl", + "Permission:PdfGeneration": "Breyta í PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/it.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/it.json new file mode 100644 index 0000000000..1616e2cecb --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/it.json @@ -0,0 +1,7 @@ +{ + "culture": "it", + "texts": { + "Permission:DocumentManagement.Common": "Gestione documenti comuni", + "Permission:PdfGeneration": "Generazione PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/nl.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/nl.json new file mode 100644 index 0000000000..64e170aaf8 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/nl.json @@ -0,0 +1,7 @@ +{ + "culture": "nl", + "texts": { + "Permission:DocumentManagement.Common": "Algemene documentbeheer", + "Permission:PdfGeneration": "PDF-generatie" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pl-PL.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pl-PL.json new file mode 100644 index 0000000000..89c83f4063 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pl-PL.json @@ -0,0 +1,7 @@ +{ + "culture": "pl-PL", + "texts": { + "Permission:DocumentManagement.Common": "Zarządzanie dokumentami", + "Permission:PdfGeneration": "Generowanie PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pt-BR.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pt-BR.json new file mode 100644 index 0000000000..e9c83fc560 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pt-BR.json @@ -0,0 +1,7 @@ +{ + "culture": "pt-BR", + "texts": { + "Permission:DocumentManagement.Common": "Gerenciamento de documentos comuns", + "Permission:PdfGeneration": "Geração de PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ro-RO.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ro-RO.json new file mode 100644 index 0000000000..b5cc16b376 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ro-RO.json @@ -0,0 +1,7 @@ +{ + "culture": "ro-RO", + "texts": { + "Permission:DocumentManagement.Common": "Gestionarea documentelor comune", + "Permission:PdfGeneration": "Generarea PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ru.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ru.json new file mode 100644 index 0000000000..f110638da1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ru.json @@ -0,0 +1,7 @@ +{ + "culture": "ru", + "texts": { + "Permission:DocumentManagement.Common": "Общее управление документами", + "Permission:PdfGeneration": "Генерация PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sk.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sk.json new file mode 100644 index 0000000000..aca12e8304 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sk.json @@ -0,0 +1,7 @@ +{ + "culture": "sk", + "texts": { + "Permission:DocumentManagement.Common": "Správa dokumentov", + "Permission:PdfGeneration": "Generovanie PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sl.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sl.json new file mode 100644 index 0000000000..1adc834a47 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sl.json @@ -0,0 +1,7 @@ +{ + "culture": "sl", + "texts": { + "Permission:DocumentManagement.Common": "Skupna dokumentna upravljanja", + "Permission:PdfGeneration": "Generiranje PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sv.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sv.json new file mode 100644 index 0000000000..c0df8c8fa9 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sv.json @@ -0,0 +1,7 @@ +{ + "culture": "sv", + "texts": { + "Permission:DocumentManagement.Common": "Dokumenthantering", + "Permission:PdfGeneration": "PDF-generering" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json new file mode 100644 index 0000000000..84166febce --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json @@ -0,0 +1,7 @@ +{ + "culture": "tr", + "texts": { + "Permission:DocumentManagement.Common": "Genel Belgeler Yönetimi", + "Permission:PdfGeneration": "PDF Oluşturma" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/vi.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/vi.json new file mode 100644 index 0000000000..e0f7a86c7d --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/vi.json @@ -0,0 +1,7 @@ +{ + "culture": "vi", + "texts": { + "Permission:DocumentManagement.Common": "Quản lý tài liệu chung", + "Permission:PdfGeneration": "Tạo PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json new file mode 100644 index 0000000000..f92de5bc99 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hans", + "texts": { + "Permission:DocumentManagement.Common": "通用文档管理", + "Permission:PdfGeneration": "PDF生成" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json new file mode 100644 index 0000000000..82b5257eed --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "Permission:DocumentManagement.Common": "通用文件管理", + "Permission:PdfGeneration": "PDF生成" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json index 6e01a9af72..f7d3533653 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json @@ -38,6 +38,7 @@ "Search": "بحث", "SearchResults": "نتائج البحث", "SearchInTheAllDocuments": "البحث في جميع الوثائق", - "GoogleTranslate": "ترجمة جوجل" + "GoogleTranslate": "ترجمة جوجل", + "DownloadPDF": "تحميل PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json index c8e6d3d19b..ed6c8767b8 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json @@ -38,6 +38,7 @@ "Search": "Vyhledávání", "SearchResults": "Výsledky vyhledávání", "SearchInTheAllDocuments": "Hledejte ve všech dokumentech", - "GoogleTranslate": "Přeložit do češtiny" + "GoogleTranslate": "Přeložit do češtiny", + "DownloadPDF": "Stáhnout PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json index 343db45f12..6a614441eb 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json @@ -38,6 +38,7 @@ "Search": "Suchen", "SearchResults": "Suchergebnisse", "SearchInTheAllDocuments": "Durchsuchen Sie alle Dokumente", - "GoogleTranslate": "Ins Deutsche übersetzen" + "GoogleTranslate": "Ins Deutsche übersetzen", + "DownloadPDF": "PDF herunterladen" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json index 21bc61b7e5..2a1a72dca2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json @@ -37,6 +37,7 @@ "Preview": "προεπισκόπηση", "Search": "Αναζήτηση", "SearchResults": "Αποτελέσματα αναζήτησης", - "GoogleTranslate": "Μετάφραση στα ελληνικά" + "GoogleTranslate": "Μετάφραση στα ελληνικά", + "DownloadPDF": "Κατέβασμα PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json index ba33bd31d6..d56e8da6df 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json @@ -35,6 +35,7 @@ "UpdatedExplanation": "Updated in the last two weeks.", "Volo.Docs.Domain:010002": "ShortName {ShortName} already exists.", "Preview": "preview", - "GoogleTranslate": "Google Translate" + "GoogleTranslate": "Google Translate", + "DownloadPDF": "Download PDF" } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json index b4414be0ea..73b07169f8 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json @@ -43,6 +43,7 @@ "ProjectDeletionWarningMessage": "Project will be deleted.", "Docs_Page_Title": "ABP Documentation", "Docs_Page_Description": "Access comprehensive guides and API references in the ABP Documentation, aiding in development and troubleshooting.", - "GoogleTranslate": "Google Translate" + "GoogleTranslate": "Google Translate", + "DownloadPDF": "Download PDF" } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json index 624d56d631..3dcd97e7fe 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json @@ -38,6 +38,7 @@ "Search": "Buscar", "SearchResults": "Resultados de la búsqueda", "SearchInTheAllDocuments": "Buscar en todos los documentos", - "GoogleTranslate": "Traducir con Google" + "GoogleTranslate": "Traducir con Google", + "DownloadPDF": "Descargar PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json index 543803bec4..db74d481a0 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json @@ -38,6 +38,7 @@ "Search": "Hae", "SearchResults": "Hakutulokset", "SearchInTheAllDocuments": "Hae kaikista asiakirjoista", - "GoogleTranslate": "Google-käännös" + "GoogleTranslate": "Google-käännös", + "DownloadPDF": "Lataa PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json index 6e8ccfffab..1bab402f73 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json @@ -38,6 +38,7 @@ "Search": "Rechercher", "SearchResults": "Résultats de recherche", "SearchInTheAllDocuments": "Rechercher dans tous les documents", - "GoogleTranslate": "Google Traduction" + "GoogleTranslate": "Google Traduction", + "DownloadPDF": "Télécharger PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json index b79c38b9b8..2ba78ec460 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json @@ -38,6 +38,7 @@ "Search": "खोज", "SearchResults": "खोज परिणाम", "SearchInTheAllDocuments": "सभी दस्तावेज़ों में खोजें", - "GoogleTranslate": "गूगल अनुवाद" + "GoogleTranslate": "गूगल अनुवाद", + "DownloadPDF": "PDF डाउनलोड करें" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json index bf71b7faed..1061dee7ab 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json @@ -38,6 +38,7 @@ "Search": "Pretraga", "SearchResults": "Rezultati pretrage", "SearchInTheAllDocuments": "Traži u svim dokumentima", - "GoogleTranslate": "Google prevoditelj" + "GoogleTranslate": "Google prevoditelj", + "DownloadPDF": "Preuzmi PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json index 1624b1b2d1..b8dee63ca4 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json @@ -38,6 +38,7 @@ "Search": "Keresés", "SearchResults": "Keresési eredmények", "SearchInTheAllDocuments": "Keressen az összes dokumentumban", - "GoogleTranslate": "Google Fordító" + "GoogleTranslate": "Google Fordító", + "DownloadPDF": "PDF letöltése" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json index 5d96a2fac5..62235d3f62 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json @@ -38,6 +38,7 @@ "Search": "Leit", "SearchResults": "Leitar niðurstöður", "SearchInTheAllDocuments": "Leitaðu í öllum skjölum", - "GoogleTranslate": "Google þýðing" + "GoogleTranslate": "Google þýðing", + "DownloadPDF": "Sækja PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json index 3983154519..91ef732c01 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json @@ -38,6 +38,7 @@ "Search": "Ricerca", "SearchResults": "Risultati della ricerca", "SearchInTheAllDocuments": "Cerca in tutti i documenti", - "GoogleTranslate": "Traduci con Google" + "GoogleTranslate": "Traduci con Google", + "DownloadPDF": "Scarica PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json index f126886009..48a82699d7 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json @@ -38,6 +38,7 @@ "Search": "Zoeken", "SearchResults": "Zoekresultaten", "SearchInTheAllDocuments": "Zoek in alle documenten", - "GoogleTranslate": "Google Vertalen" + "GoogleTranslate": "Google Vertalen", + "DownloadPDF": "PDF downloaden" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json index 5d5c58ea3f..35ae3e6801 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json @@ -38,6 +38,7 @@ "Search": "Szukaj", "SearchResults": "Wyniki wyszukiwania", "SearchInTheAllDocuments": "Szukaj we wszystkich dokumentach", - "GoogleTranslate": "Tłumaczenie na polski" + "GoogleTranslate": "Tłumaczenie na polski", + "DownloadPDF": "Pobierz PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json index 0e4143f9ac..497f0c93e2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json @@ -38,6 +38,7 @@ "Search": "Procurar", "SearchResults": "Procurar Resultados", "SearchInTheAllDocuments": "Pesquise em todos os documentos", - "GoogleTranslate": "Traduzir com Google" + "GoogleTranslate": "Traduzir com Google", + "DownloadPDF": "Baixar PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json index eaf9016463..155dad0754 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json @@ -38,6 +38,7 @@ "Search": "Caută", "SearchResults": "Rezultatele căutării", "SearchInTheAllDocuments": "Căutați în toate documentele", - "GoogleTranslate": "Traducere Google" + "GoogleTranslate": "Traducere Google", + "DownloadPDF": "Descărcare PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json index ae4b2a564d..2b5a200187 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json @@ -38,6 +38,7 @@ "Search": "Поиск", "SearchResults": "результаты поиска", "SearchInTheAllDocuments": "Искать во всех документах", - "GoogleTranslate": "Google Translate" + "GoogleTranslate": "Google Translate", + "DownloadPDF": "Скачать PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json index 54f981e98f..8f0f246a16 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json @@ -38,6 +38,7 @@ "Search": "Vyhľadať", "SearchResults": "Výsledky vyhľadávania", "SearchInTheAllDocuments": "Vyhľadajte vo všetkých dokumentoch", - "GoogleTranslate": "Google preklad" + "GoogleTranslate": "Google preklad", + "DownloadPDF": "Stiahnuť PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json index 3d326a5127..c182e66b3e 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json @@ -38,6 +38,7 @@ "Search": "Iskanje", "SearchResults": "Rezultati iskanja", "SearchInTheAllDocuments": "Poiščite v vseh dokumentih", - "GoogleTranslate": "Google prevajalnik" + "GoogleTranslate": "Google prevajalnik", + "DownloadPDF": "Prenesi PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json index 2ec28362f0..29db42be57 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json @@ -43,6 +43,7 @@ "ProjectDeletionWarningMessage": "Projektet kommer att raderas.", "Docs_Page_Title": "ABP-dokumentation", "Docs_Page_Description": "Få tillgång till omfattande guider och API-referenser i ABP Documentation, vilket underlättar utveckling och felsökning.", - "GoogleTranslate": "Google Översätt" + "GoogleTranslate": "Google Översätt", + "DownloadPDF": "Ladda ner PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json index 0e9619ce4d..35b08c6a62 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json @@ -37,6 +37,7 @@ "Preview": "ön izleme", "Search": "Arama", "SearchResults": "Arama Sonuçları", - "GoogleTranslate": "Google Çeviri" + "GoogleTranslate": "Google Çeviri", + "DownloadPDF": "PDF İndir" } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json index 612bcad36a..d6916d05ad 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json @@ -38,6 +38,7 @@ "Search": "Tìm kiếm", "SearchResults": "kết quả tìm kiếm", "SearchInTheAllDocuments": "Tìm kiếm trong tất cả các tài liệu", - "GoogleTranslate": "Dịch Google" + "GoogleTranslate": "Dịch Google", + "DownloadPDF": "Tải xuống PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json index 4aaac66120..d214b9b4a6 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json @@ -38,6 +38,7 @@ "Search": "搜索", "SearchResults": "搜索结果", "SearchInTheAllDocuments": "在所有文档中搜索", - "GoogleTranslate": "谷歌翻译" + "GoogleTranslate": "谷歌翻译", + "DownloadPDF": "下载PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json index 8f2a6ea86e..ee4a291b61 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json @@ -38,6 +38,7 @@ "Search": "搜索", "SearchResults": "搜索結果", "SearchInTheAllDocuments": "在所有文件中搜尋", - "GoogleTranslate": "谷歌翻譯" + "GoogleTranslate": "谷歌翻譯", + "DownloadPDF": "下載PDF" } } \ No newline at end of file From c0ca2fcfc801d2e9f52000d6341a43dfbd6e3638 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 21 Apr 2025 13:55:59 +0800 Subject: [PATCH 05/19] Update appsettings.json --- modules/docs/app/VoloDocs.Migrator/appsettings.json | 2 +- modules/docs/app/VoloDocs.Web/appsettings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/docs/app/VoloDocs.Migrator/appsettings.json b/modules/docs/app/VoloDocs.Migrator/appsettings.json index 91cbfffb2f..9668adc1e2 100644 --- a/modules/docs/app/VoloDocs.Migrator/appsettings.json +++ b/modules/docs/app/VoloDocs.Migrator/appsettings.json @@ -1,3 +1,3 @@ { - "ConnectionString": "Server=localhost;Database=VoloDocs;user=sa;password=admin@123456;TrustServerCertificate=True" + "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;TrustServerCertificate=True", } \ No newline at end of file diff --git a/modules/docs/app/VoloDocs.Web/appsettings.json b/modules/docs/app/VoloDocs.Web/appsettings.json index 5a8ec7a2da..38400900f4 100644 --- a/modules/docs/app/VoloDocs.Web/appsettings.json +++ b/modules/docs/app/VoloDocs.Web/appsettings.json @@ -12,7 +12,7 @@ "Redis": { "Configuration": "127.0.0.1" }, - "ConnectionString": "Server=localhost;Database=VoloDocs;user=sa;password=admin@123456;TrustServerCertificate=True", + "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;TrustServerCertificate=True", "ElasticSearch": { "Url": "http://localhost:9200" }, From e96f601641ab8a4bb7d704d3b9df2c00517d96f6 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 22 Apr 2025 14:20:47 +0800 Subject: [PATCH 06/19] Handle anchor links --- .../Docs/Admin/Projects/DeletePdfFileInput.cs | 2 +- .../Admin/Projects/ProjectAdminAppService.cs | 2 +- .../docs-admin-generate-proxy.json | 2 +- .../Pages/Docs/Admin/Projects/generatePdf.js | 2 + .../client-proxies/docs-admin-proxy.js | 2 +- .../Volo/Docs/Documents/DocumentAppService.cs | 14 +-- .../Volo/Docs}/Utils/UrlHelper.cs | 0 .../Documents/Pdf/BlobDocumentPdfFileStore.cs | 2 +- .../Pdf/DocsDocumentPdfGeneratorOptions.cs | 1 - .../Documents/Pdf/DocumentPdfGenerator.cs | 113 ++++++++++-------- .../Documents/Pdf/IText/ITextPdfRenderer.cs | 6 +- .../Pdf/Markdig/AnchorLinkRenderer.cs | 65 ++++++++++ .../Markdig/AnchorLinkResolverExtension.cs | 27 +++++ 13 files changed, 167 insertions(+), 71 deletions(-) rename modules/docs/src/{Volo.Docs.Web => Volo.Docs.Domain.Shared/Volo/Docs}/Utils/UrlHelper.cs (100%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkRenderer.cs create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkResolverExtension.cs diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs index 074553cf46..6e8e30e57c 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs @@ -4,7 +4,7 @@ namespace Volo.Docs.Admin.Projects; public class DeletePdfFileInput { - public Guid Id { get; set; } + public Guid ProjectId { get; set; } public string Version { get; set; } diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs index 3ed75c4b84..a5d61aa358 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs @@ -185,7 +185,7 @@ namespace Volo.Docs.Admin.Projects public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) { - await _documentPdfCache.RemoveAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(input.Id, input.Version, input.LanguageCode)); + await _documentPdfCache.RemoveAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(input.ProjectId, input.Version, input.LanguageCode)); } } } diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json index 36f81f8d46..96eddc28ee 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json @@ -1021,7 +1021,7 @@ "parameters": [ { "nameOnMethod": "input", - "name": "Id", + "name": "ProjectId", "jsonName": null, "type": "System.Guid", "typeSimple": "string", diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js index 7be870f6b6..e65f978690 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js @@ -24,6 +24,7 @@ $(function () { $("#GeneratePdfBtn").click(function () { var $btn = $(this); $btn.buttonBusy(true); + $("#GenerateAndDownloadPdfBtn").buttonBusy(true); var input = { projectId: $("#ProjectId").val(), version: $("#Version").val(), @@ -36,6 +37,7 @@ $(function () { if (jqXHR.status === 200) { abp.message.success("PDF generated successfully."); $btn.buttonBusy(false); + $("#GenerateAndDownloadPdfBtn").buttonBusy(false); } else { abp.ajax.handleErrorStatusCode(jqXHR.status); } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js index 9afc61c17e..60bab5146a 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js @@ -138,7 +138,7 @@ volo.docs.admin.projectsAdmin.deletePdfFile = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/admin/projects/DeletePdfFile' + abp.utils.buildQueryString([{ name: 'id', value: input.id }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + url: abp.appPath + 'api/docs/admin/projects/DeletePdfFile' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', type: 'DELETE', dataType: null }, ajaxParams)); diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs index c156b669dd..e5bbca3f5a 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs @@ -17,6 +17,7 @@ using Volo.Docs.Caching; using Volo.Docs.Common.Projects; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Docs.Projects; +using Volo.Docs.Utils; using Volo.Extensions; namespace Volo.Docs.Documents @@ -282,7 +283,7 @@ namespace Volo.Docs.Documents private List GetDocumentLinks(NavigationNode node, List documentUrls, string prefix, string shortName, DocumentWithoutDetails document) { - if (!IsExternalLink(node.Path)) + if (!UrlHelper.IsExternalLink(node.Path)) { documentUrls.AddIfNotContains( NormalizePath(prefix, node.Path, shortName, document) @@ -320,17 +321,6 @@ namespace Volo.Docs.Documents : path; } - private static bool IsExternalLink(string path) - { - if (path.IsNullOrEmpty()) - { - return false; - } - - return path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || - path.StartsWith("https://", StringComparison.OrdinalIgnoreCase); - } - public virtual async Task GetParametersAsync(GetParametersDocumentInput input) { var project = await _projectRepository.GetAsync(input.ProjectId); diff --git a/modules/docs/src/Volo.Docs.Web/Utils/UrlHelper.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Utils/UrlHelper.cs similarity index 100% rename from modules/docs/src/Volo.Docs.Web/Utils/UrlHelper.cs rename to modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Utils/UrlHelper.cs diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs index 9ddb076d3b..1415bf73f0 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs @@ -28,7 +28,7 @@ public class BlobDocumentPdfFileStore : IDocumentPdfFileStore, ITransientDepende public virtual async Task SetAsync(Project project, string version, string languageCode, Stream stream) { - await BlobContainer.SaveAsync(Options.Value.CalculatePdfFileName(project, version, languageCode), stream); + await BlobContainer.SaveAsync(Options.Value.CalculatePdfFileName(project, version, languageCode), stream, true); await Cache.SetAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(project.Id, version, languageCode), new DocsDocumentPdfCacheItem(), new DistributedCacheEntryOptions diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs index 606eef2d4a..0b9dcfcca6 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs @@ -64,7 +64,6 @@ public class DocsDocumentPdfGeneratorOptions pre { position: relative; padding: 16px; - padding-top: calc(16px * 2.5); border-radius: 8px; border: 1px solid #e2e8f0; } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs index fea0d488b4..f9b8185602 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; -using System.Threading; using System.Threading.Tasks; using System.Web; using Markdig; @@ -14,10 +13,10 @@ using Microsoft.Extensions.Options; using Volo.Abp; using Volo.Abp.Content; using Volo.Abp.DependencyInjection; -using Volo.Abp.Threading; -using Volo.Docs.Documents.Pdf.IText; +using Volo.Docs.Documents.Pdf.Markdig; using Volo.Docs.Documents.Rendering; using Volo.Docs.Projects; +using Volo.Docs.Utils; using Volo.Extensions; namespace Volo.Docs.Documents.Pdf; @@ -33,10 +32,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency protected ILogger Logger { get; set; } protected IDocumentSource DocumentSource { get; set; } protected DocumentParams DocumentParams { get; set; } - protected List AllPdfDocumentNodes { get; set; } = []; - protected MarkdownPipeline MarkdownPipeline { get; } = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build(); - - private readonly SemaphoreSlim _syncSemaphore; + protected List AllPdfDocumentNodes { get; } = []; public DocumentPdfGenerator( IDocumentSourceFactory documentStoreFactory, @@ -53,33 +49,29 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency DocumentPdfFileStore = documentPdfFileStore; PdfRenderer = pdfRenderer; Logger = NullLogger.Instance; - _syncSemaphore = new SemaphoreSlim(1, 1); } public virtual async Task GenerateAsync(Project project, string version, string languageCode) { - using (await _syncSemaphore.LockAsync()) - { - var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); - var fileStream = await DocumentPdfFileStore.GetOrNullAsync(project, version, languageCode); - - if (fileStream != null) - { - return new RemoteStreamContent(fileStream, fileName, "application/pdf"); - } - - DocumentSource = DocumentStoreFactory.Create(project.DocumentStoreType); - DocumentParams = await GetDocumentParamsAsync(project, version, languageCode); - var navigation = await GetNavigationAsync(project, version, languageCode); + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + var fileStream = await DocumentPdfFileStore.GetOrNullAsync(project, version, languageCode); - await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode); - var htmlContent = await ConvertDocumentsToHtmlAsync(AllPdfDocumentNodes); + if (fileStream != null) + { + return new RemoteStreamContent(fileStream, fileName, "application/pdf"); + } - var pdfStream = await PdfRenderer.GeneratePdfAsync(htmlContent, AllPdfDocumentNodes); - await DocumentPdfFileStore.SetAsync(project, version, languageCode, pdfStream); + DocumentSource = DocumentStoreFactory.Create(project.DocumentStoreType); + DocumentParams = await GetDocumentParamsAsync(project, version, languageCode); + var navigation = await GetNavigationAsync(project, version, languageCode); + + await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode); + var htmlContent = await ConvertDocumentsToHtmlAsync(AllPdfDocumentNodes); - return new RemoteStreamContent(pdfStream, fileName, "application/pdf"); - } + var pdfStream = await PdfRenderer.GeneratePdfAsync(htmlContent, AllPdfDocumentNodes); + await DocumentPdfFileStore.SetAsync(project, version, languageCode, pdfStream); + + return new RemoteStreamContent(pdfStream, fileName, "application/pdf"); } protected virtual async Task ConvertDocumentsToHtmlAsync(List pdfDocumentNodes) @@ -91,7 +83,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency if (pdfDocumentNode.Document != null) { var renderedDocument = await RenderDocumentAsync(pdfDocumentNode); - renderedDocument = NormalizeHtmlContent(pdfDocumentNode, Markdown.ToHtml(renderedDocument, MarkdownPipeline)); + renderedDocument = NormalizeHtmlContent(pdfDocumentNode, Markdown.ToHtml(renderedDocument, GetMarkdownPipeline(pdfDocumentNode))); contentBuilder.AppendLine(renderedDocument); } @@ -106,7 +98,8 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency protected virtual async Task RenderDocumentAsync(PdfDocumentNode pdfDocumentNode) { - var renderedDocument = await DocumentSectionRenderer.RenderAsync(pdfDocumentNode.Document.Content, pdfDocumentNode.RenderParameters); + var content = NormalizeMarkdownContent(pdfDocumentNode.Document.Content); + var renderedDocument = await DocumentSectionRenderer.RenderAsync(content, pdfDocumentNode.RenderParameters); if (pdfDocumentNode.RenderParameters != null) { renderedDocument = SetDocumentTitle(renderedDocument, pdfDocumentNode.Title); @@ -136,8 +129,8 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency Title = navigation.Text, IgnoreOnOutline = navigation.Path == Options.Value.CoverPagePath }; - - if (!navigation.Path.IsNullOrWhiteSpace()) + + if (!navigation.Path.IsNullOrWhiteSpace() && !navigation.HasChildItems) { var path = NormalizeNavigationPath(navigation.Path); var document = await GetDocumentAsync(project, path, version, languageCode); @@ -147,19 +140,12 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency pdfDocumentNode.Document = document; pdfDocumentNode.Title = GetDocumentTitle(navigation.Text, document.Content, firstParameterCombination); - pdfDocumentNode.Id = GetDocumentId(navigation.Path, firstParameterCombination); + pdfDocumentNode.Id = GetDocumentId(path, firstParameterCombination, true); pdfDocumentNode.RenderParameters = firstParameterCombination; - + if(parameters.Count <= 1) { - if (parentPdfDocumentNode == null) - { - AllPdfDocumentNodes.AddRange(parameterCombinationsDocuments); - } - else - { - parentPdfDocumentNode.Children.AddRange(parameterCombinationsDocuments); - } + AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments); } else { @@ -170,7 +156,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency { Document = document, Title = GetDocumentTitle(navigation.Text, document.Content, parameterCombination), - Id = GetDocumentId(navigation.Path, parameterCombination), + Id = GetDocumentId(path, parameterCombination, false), RenderParameters = parameterCombination }); } @@ -190,6 +176,11 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency { await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode, pdfDocumentNode); } + + if (navigation == navigations.Last()) + { + AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments); + } } catch (Exception e) { @@ -198,6 +189,18 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency } } + private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, List parameterCombinationsDocuments) + { + if (parentPdfDocumentNode == null) + { + AllPdfDocumentNodes.AddRange(parameterCombinationsDocuments); + } + else + { + parentPdfDocumentNode.Children.AddRange(parameterCombinationsDocuments); + } + } + private string NormalizeNavigationPath(string path) { return !path.EndsWith(".md") ? Path.Combine(path, "index.md") : path; @@ -330,15 +333,15 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency var paramValues = parameters.Select(x => $"{DocumentParams.Parameters.FirstOrDefault(p => p.Name == x.Key)?.DisplayName ?? x.Key}: {x.Value}").ToList(); return titleLine.TrimStart('#').Trim() + $" ({string.Join(", ", paramValues)})"; } - - private string GetDocumentId(string path, DocumentRenderParameters parameters) + private string GetDocumentId(string path, DocumentRenderParameters parameters, bool isFirstCombinationDocument) { var id = path.Replace(".md",string.Empty).Replace("/","-").Replace(" ", "-").ToLower(); - if (parameters != null) + if (parameters != null && !isFirstCombinationDocument) { id = $"{id}{parameters.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-")}"; } + return id; } @@ -354,12 +357,12 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency { return Regex.Replace(htmlContent, @"(]*)src=""([^""]*)""([^>]*>)", delegate (Match match) { - if (IsExternalLink(match.Groups[2].Value)) + if (UrlHelper.IsExternalLink(match.Groups[2].Value)) { return match.Value; } - var rootUrl = IsExternalLink(pdfDocumentNode.Document.RawRootUrl) + var rootUrl = UrlHelper.IsExternalLink(pdfDocumentNode.Document.RawRootUrl) ? pdfDocumentNode.Document.RawRootUrl.EnsureEndsWith('/') : Options.Value.BaseUrl.EnsureEndsWith('/') + pdfDocumentNode.Document.RawRootUrl.TrimStart('/').EnsureEndsWith('/'); var newImageSource = rootUrl + @@ -370,10 +373,18 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency }, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline); } - - private bool IsExternalLink(string link) + + private string NormalizeMarkdownContent(string content) + { + var pattern = @"````json\s*//$begin:math:display$doc-nav$end:math:display$[\s\S]*?````"; + return Regex.Replace(content, pattern, string.Empty, RegexOptions.IgnoreCase); + } + + private MarkdownPipeline GetMarkdownPipeline(PdfDocumentNode pdfDocumentNode) { - return link.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || - link.StartsWith("https://", StringComparison.OrdinalIgnoreCase); + return new MarkdownPipelineBuilder() + .UseAdvancedExtensions() + .Use(new AnchorLinkResolverExtension(pdfDocumentNode)) + .Build(); } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs index f4164dfd3a..133d8b008f 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs @@ -21,7 +21,7 @@ public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency Options = options; } - public virtual Task GeneratePdfAsync(string htmlContent, List pdfDocumentNodes) + public virtual async Task GeneratePdfAsync(string htmlContent, List pdfDocumentNodes) { var pdfStream = new MemoryStream(); var pdfWrite = new PdfWriter(pdfStream); @@ -38,6 +38,8 @@ public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); converter.SetTagWorkerFactory(tagWorkerFactory); + + await File.WriteAllTextAsync("/Users/liangshiweis/codes/test.html", htmlBuilder.ToString()); HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter); tagWorkerFactory.AddNamedDestinations(); @@ -46,7 +48,7 @@ public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency textDocument.Close(); pdfStream.Position = 0; - return Task.FromResult(pdfStream); + return pdfStream; } private void BuildPdfOutlines(PdfOutline parentOutline, List pdfDocumentNodes) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkRenderer.cs new file mode 100644 index 0000000000..7f8d65d4ff --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkRenderer.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Markdig.Renderers; +using Markdig.Renderers.Html.Inlines; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; +using Volo.Docs.Utils; + +namespace Volo.Docs.Documents.Pdf.Markdig; + +public class AnchorLinkRenderer : LinkInlineRenderer +{ + private readonly PdfDocumentNode _documentNode; + + public AnchorLinkRenderer(PdfDocumentNode documentNode) + { + _documentNode = documentNode; + } + + protected override void Write(HtmlRenderer renderer, LinkInline link) + { + if (UrlHelper.IsExternalLink(link.Url) || link.Url.IsNullOrWhiteSpace() || link.IsImage) + { + base.Write(renderer, link); + return; + } + + var anchor = ResolveRelativeMarkdownPath(_documentNode.Document.Name, link.Url) + .Replace(".md",string.Empty).Replace("/","-").Replace(" ", "-").ToLower(); + + renderer.Write(""); + renderer.Write(link.FirstChild?.ToString() ?? anchor); + renderer.Write(""); + } + + private string ResolveRelativeMarkdownPath(string currentPath, string relativePath) + { + currentPath = currentPath.EnsureStartsWith('/'); + relativePath = relativePath.EnsureStartsWith('/'); + + var currentDir = currentPath.Substring(0, currentPath.LastIndexOf('/')); + + var baseParts = currentDir.Split('/', StringSplitOptions.RemoveEmptyEntries).ToList(); + var relativeParts = relativePath.Split('/', StringSplitOptions.RemoveEmptyEntries); + + foreach (var part in relativeParts) + { + if (part == "..") + { + if (baseParts.Count > 0) + { + baseParts.RemoveAt(baseParts.Count - 1); + } + } + else if (part != ".") + { + baseParts.Add(part); + } + } + + return string.Join("/", baseParts); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkResolverExtension.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkResolverExtension.cs new file mode 100644 index 0000000000..d8a66b368a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkResolverExtension.cs @@ -0,0 +1,27 @@ +using Markdig; +using Markdig.Renderers; +using Markdig.Renderers.Html.Inlines; + +namespace Volo.Docs.Documents.Pdf.Markdig; + +public class AnchorLinkResolverExtension : IMarkdownExtension +{ + private readonly PdfDocumentNode _documentNode; + + public AnchorLinkResolverExtension(PdfDocumentNode documentNode) + { + _documentNode = documentNode; + } + + public void Setup(MarkdownPipelineBuilder pipeline) + { + } + + public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) + { + if (renderer is HtmlRenderer htmlRenderer) + { + htmlRenderer.ObjectRenderers.Replace(new AnchorLinkRenderer(_documentNode)); + } + } +} \ No newline at end of file From d5d282c418b5322e08d11b57357c718551761a18 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 22 Apr 2025 16:41:18 +0800 Subject: [PATCH 07/19] Support preview --- .../app/VoloDocs.Web/VoloDocsWebModule.cs | 2 +- .../DocsDocumentPdfGeneratorController.cs | 6 ++- .../Pdf/DocsDocumentPdfGeneratorOptions.cs | 38 +++++++++++++---- .../Documents/Pdf/DocumentPdfGenerator.cs | 41 +++++++++++-------- .../Documents/Pdf/IText/ITextPdfRenderer.cs | 4 +- 5 files changed, 61 insertions(+), 30 deletions(-) diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index a0996f51df..8702ac6500 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -178,7 +178,7 @@ namespace VoloDocs.Web Configure(options => { options.BaseUrl = configuration["App:selfUrl"]; - options.CoverPagePath = "Index.md"; + options.IndexPagePath = "Index.md"; }); Configure(options => diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs index bfd5be9224..31ae2a2f44 100644 --- a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs @@ -23,8 +23,10 @@ public class DocsDocumentPdfGeneratorController : DocsControllerBase, IDocumentP [HttpGet] [Route("pdf")] - public Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + public async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) { - return DocumentPdfGeneratorAppService.GeneratePdfAsync(input); + var streamContent = await DocumentPdfGeneratorAppService.GeneratePdfAsync(input); + Response.Headers.ContentDisposition = $"inline; filename=\"{streamContent.FileName}\""; + return streamContent; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs index 0b9dcfcca6..59a25628ae 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs @@ -12,14 +12,34 @@ public class DocsDocumentPdfGeneratorOptions /// The HTML layout for the PDF document. /// public string HtmlLayout { get; set; } - public string HtmlStyles { get; set; } + + /// + /// The HTML style for the PDF document. + /// + public string HtmlStyle { get; set; } + + /// + /// The base URL for the PDF document. + /// Used for resolving relative links and images. + /// public string BaseUrl { get; set; } - public string CoverPagePath { get; set; } - public TimeSpan PdfFileCacheExpiration { get; set; } = TimeSpan.FromDays(1); - public Func CalculatePdfFileName { get; set; } = (project, version, languageCode) => - { - return $"{project.ShortName}_{version}_{languageCode}.pdf"; - }; + + /// + /// The path to the index page of the documentation. + /// + public string IndexPagePath { get; set; } + + /// + /// PDF file cache expiration time. + /// Default value is 24 hours. + /// + public TimeSpan PdfFileCacheExpiration { get; set; } = TimeSpan.FromHours(24); + + /// + /// The function to calculate the PDF file name. + /// Default is "{project.ShortName}_{version}_{languageCode}.pdf". + /// + public Func CalculatePdfFileName { get; set; } public DocsDocumentPdfGeneratorOptions() { @@ -36,7 +56,7 @@ public class DocsDocumentPdfGeneratorOptions "; - HtmlStyles = @" + HtmlStyle = @" body { margin: 20px; line-height: 1.6; font-family: Arial, sans-serif;} a { text-decoration: none; } .page { @@ -73,5 +93,7 @@ public class DocsDocumentPdfGeneratorOptions padding: 10px 20px; background: #f8fafc; }"; + + CalculatePdfFileName = (project, version, languageCode) => $"{project.ShortName}_{version}_{languageCode}.pdf"; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs index f9b8185602..caa3dd38ff 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs @@ -115,7 +115,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency string languageCode, PdfDocumentNode parentPdfDocumentNode = null) { - var parameterCombinationsDocuments = new List(); + var groupedCombinationsDocuments = new Dictionary>(); foreach (var navigation in navigations) { if (navigation.IgnoreOnDownload) @@ -127,7 +127,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency var pdfDocumentNode = new PdfDocumentNode { Title = navigation.Text, - IgnoreOnOutline = navigation.Path == Options.Value.CoverPagePath + IgnoreOnOutline = navigation.Path == Options.Value.IndexPagePath }; if (!navigation.Path.IsNullOrWhiteSpace() && !navigation.HasChildItems) @@ -145,14 +145,20 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency if(parameters.Count <= 1) { - AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments); + AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments); } else { for (var i = 1; i < parameterCombinations.Count; i++) { var parameterCombination = parameterCombinations[i]; - parameterCombinationsDocuments.Add(new PdfDocumentNode + var key = parameterCombination.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-"); + if (!groupedCombinationsDocuments.ContainsKey(key)) + { + groupedCombinationsDocuments[key] = []; + } + + groupedCombinationsDocuments[key].Add(new PdfDocumentNode { Document = document, Title = GetDocumentTitle(navigation.Text, document.Content, parameterCombination), @@ -179,7 +185,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency if (navigation == navigations.Last()) { - AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments); + AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments); } } catch (Exception e) @@ -189,15 +195,18 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency } } - private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, List parameterCombinationsDocuments) + private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, Dictionary> groupedCombinationsDocuments) { - if (parentPdfDocumentNode == null) - { - AllPdfDocumentNodes.AddRange(parameterCombinationsDocuments); - } - else - { - parentPdfDocumentNode.Children.AddRange(parameterCombinationsDocuments); + foreach (var combinations in groupedCombinationsDocuments) + { + if (parentPdfDocumentNode == null) + { + AllPdfDocumentNodes.AddRange(combinations.Value); + } + else + { + parentPdfDocumentNode.Children.AddRange(combinations.Value); + } } } @@ -218,11 +227,11 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency throw new UserFriendlyException($"Cannot validate navigation file '{project.NavigationDocumentName}' for the project {project.Name}."); } - if (!Options.Value.CoverPagePath.IsNullOrWhiteSpace()) + if (!Options.Value.IndexPagePath.IsNullOrWhiteSpace()) { navigation.Items.Insert(0, new NavigationNode { - Path = Options.Value.CoverPagePath + Path = Options.Value.IndexPagePath }); } @@ -376,7 +385,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency private string NormalizeMarkdownContent(string content) { - var pattern = @"````json\s*//$begin:math:display$doc-nav$end:math:display$[\s\S]*?````"; + var pattern = @"`{3,4}json\s*//\[doc-nav\][\s\S]*?`{3,4}"; return Regex.Replace(content, pattern, string.Empty, RegexOptions.IgnoreCase); } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs index 133d8b008f..2634a34724 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs @@ -31,15 +31,13 @@ public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency var htmlBuilder = new StringBuilder(); htmlBuilder.Append(Options.Value.HtmlLayout); - htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyles); + htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyle); htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.ContentPlaceholder, htmlContent); var converter = new ConverterProperties(); var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); converter.SetTagWorkerFactory(tagWorkerFactory); - - await File.WriteAllTextAsync("/Users/liangshiweis/codes/test.html", htmlBuilder.ToString()); HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter); tagWorkerFactory.AddNamedDestinations(); From 2a39420dc93d8030028da7268df517aeb31e2dfa Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 22 Apr 2025 16:48:24 +0800 Subject: [PATCH 08/19] Update DocsDocumentPdfGeneratorOptions.cs --- .../Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs index 59a25628ae..cf99c30991 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs @@ -37,7 +37,7 @@ public class DocsDocumentPdfGeneratorOptions /// /// The function to calculate the PDF file name. - /// Default is "{project.ShortName}_{version}_{languageCode}.pdf". + /// Default is "{project.ShortName}-{version}-{languageCode}.pdf". /// public Func CalculatePdfFileName { get; set; } @@ -94,6 +94,6 @@ public class DocsDocumentPdfGeneratorOptions background: #f8fafc; }"; - CalculatePdfFileName = (project, version, languageCode) => $"{project.ShortName}_{version}_{languageCode}.pdf"; + CalculatePdfFileName = (project, version, languageCode) => $"{project.ShortName}-{version}-{languageCode}.pdf"; } } \ No newline at end of file From 0219d40a5adfb72c905cbd7eba18026d78df4418 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 24 Apr 2025 13:39:41 +0800 Subject: [PATCH 09/19] Update modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SALİH ÖZKARA --- .../Localization/Resources/Docs/ApplicationContracts/tr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json index 84166febce..19c39d619b 100644 --- a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json @@ -1,7 +1,7 @@ { "culture": "tr", "texts": { - "Permission:DocumentManagement.Common": "Genel Belgeler Yönetimi", + "Permission:DocumentManagement.Common": "Genel Belge Yönetimi", "Permission:PdfGeneration": "PDF Oluşturma" } } \ No newline at end of file From c455834f3370b3e40b23fbc8a6f5dd3d5b41a41b Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 24 Apr 2025 13:44:56 +0800 Subject: [PATCH 10/19] Update modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SALİH ÖZKARA --- modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj index 0dc06c6d56..e57312e16b 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj +++ b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj @@ -25,7 +25,6 @@ - From 056502c0fdebe9ee7a4bf0b8a8ef4e23ff211f17 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 28 Apr 2025 15:40:39 +0800 Subject: [PATCH 11/19] Abstract PDF Generation and add Manage PDF files feature --- .../20250425082043_add_pdf_file.Designer.cs | 1376 +++++++++++++++++ .../Migrations/20250425082043_add_pdf_file.cs | 44 + .../VoloDocsDbContextModelSnapshot.cs | 41 + .../app/VoloDocs.Web/VoloDocsWebModule.cs | 4 +- .../DocsAdminPermissionDefinitionProvider.cs | 1 + .../Volo/Docs/Admin/DocsAdminPermissions.cs | 1 + .../Docs/ApplicationContracts/ar.json | 5 +- .../Docs/ApplicationContracts/cs.json | 5 +- .../Docs/ApplicationContracts/de-DE.json | 5 +- .../Docs/ApplicationContracts/de.json | 5 +- .../Docs/ApplicationContracts/el.json | 5 +- .../Docs/ApplicationContracts/en-GB.json | 5 +- .../Docs/ApplicationContracts/en.json | 5 +- .../Docs/ApplicationContracts/es.json | 5 +- .../Docs/ApplicationContracts/fi.json | 5 +- .../Docs/ApplicationContracts/fr.json | 5 +- .../Docs/ApplicationContracts/hi.json | 5 +- .../Docs/ApplicationContracts/hr.json | 5 +- .../Docs/ApplicationContracts/hu.json | 5 +- .../Docs/ApplicationContracts/is.json | 5 +- .../Docs/ApplicationContracts/it.json | 5 +- .../Docs/ApplicationContracts/nl.json | 5 +- .../Docs/ApplicationContracts/pl-PL.json | 5 +- .../Docs/ApplicationContracts/pt-BR.json | 5 +- .../Docs/ApplicationContracts/ro-RO.json | 5 +- .../Docs/ApplicationContracts/ru.json | 5 +- .../Docs/ApplicationContracts/sk.json | 5 +- .../Docs/ApplicationContracts/sl.json | 5 +- .../Docs/ApplicationContracts/sv.json | 5 +- .../Docs/ApplicationContracts/tr.json | 5 +- .../Docs/ApplicationContracts/vi.json | 5 +- .../Docs/ApplicationContracts/zh-Hans.json | 5 +- .../Docs/ApplicationContracts/zh-Hant.json | 5 +- .../Docs/Admin/Projects/GetPdfFilesInput.cs | 9 + .../Admin/Projects/IProjectAdminAppService.cs | 2 + .../Docs/Admin/Projects/ProjectPdfFileDto.cs | 14 + .../DocsAdminApplicationAutoMapperProfile.cs | 1 + .../Admin/Projects/ProjectAdminAppService.cs | 32 +- .../ProjectsAdminClientProxy.Generated.cs | 8 + .../docs-admin-generate-proxy.json | 90 ++ .../Docs/Admin/ProjectsAdminController.cs | 7 + .../Docs/Admin/Projects/GeneratePdf.cshtml | 2 +- .../Pages/Docs/Admin/Projects/Index.cshtml | 1 + .../Docs/Admin/Projects/ManagePdfFiles.cshtml | 41 + .../Admin/Projects/ManagePdfFiles.cshtml.cs | 14 + .../Pages/Docs/Admin/Projects/generatePdf.js | 54 +- .../Pages/Docs/Admin/Projects/index.js | 12 +- .../Docs/Admin/Projects/managePdfFiles.js | 94 ++ .../client-proxies/docs-admin-proxy.js | 7 + .../DocsCommonPermissionDefinitionProvider.cs | 2 +- .../Volo/Docs/Common/DocsCommonPermissions.cs | 2 +- .../DocumentPdfGeneratorAppService.cs | 15 +- .../Volo/Docs/Documents/DocumentParams.cs | 4 +- .../DocumentToHtmlConverterFactory.cs | 4 +- .../DocumentToHtmlConverterOptions.cs | 14 + .../IDocumentToHtmlConverter.cs | 9 + .../IDocumentToHtmlConverterFactory.cs | 6 + .../Volo/Docs/DocsDomainConsts.cs | 1 + .../Volo/Docs/DocsDomainModule.cs | 8 + .../Documents/Pdf/BlobDocumentPdfFileStore.cs | 50 - .../Documents/Pdf/DocsDocumentPdfCacheItem.cs | 11 - .../Volo/Docs/Documents/Pdf/IPdfRenderer.cs | 10 - .../Volo/Docs/Projects/IProjectRepository.cs | 2 +- .../Projects/Pdf/BlobProjectPdfFileStore.cs | 64 + .../Pdf/DocsProjectPdfContainer.cs} | 4 +- .../Pdf/DocsProjectPdfGeneratorOptions.cs} | 7 +- .../Docs/Projects/Pdf/IHtmlToPdfRenderer.cs | 10 + .../Pdf/IProjectPdfFileStore.cs} | 5 +- .../Pdf/IProjectPdfGenerator.cs} | 5 +- .../Pdf/IText/HtmlIdTagWorkerFactory.cs | 7 +- .../Pdf/IText/ITextHtmlToPdfRenderer.cs} | 26 +- .../Pdf/Markdown}/AnchorLinkRenderer.cs | 13 +- .../Markdown}/AnchorLinkResolverExtension.cs | 10 +- .../MarkdigPdfDocumentToHtmlConverter.cs | 73 + .../Pdf/PdfDocument.cs} | 7 +- .../Pdf/PdfDocumentToHtmlConverterContext.cs | 13 + .../Pdf/ProjectPdfGenerator.cs} | 292 ++-- .../Volo/Docs/Projects/Project.cs | 23 + .../Volo/Docs/Projects/ProjectPdfFile.cs | 38 + .../Docs/EntityFrameworkCore/DocsDbContext.cs | 2 + .../DocsDbContextModelBuilderExtensions.cs | 15 + .../DocsEfCoreQueryableExtensions.cs | 6 + .../EntityFrameworkCore/IDocsDbContext.cs | 2 + .../Docs/Projects/EfCoreProjectRepository.cs | 14 +- .../Docs/Projects/MongoProjectRepository.cs | 7 +- .../DocumentToHtmlConverterContext.cs | 26 + .../DocumentToHtmlConverterOptions.cs | 15 - .../IDocumentToHtmlConverter.cs | 10 - .../IDocumentToHtmlConverterFactory.cs | 7 - .../MarkdownDocumentToHtmlConverter.cs | 19 +- .../Pages/Documents/Project/Index.cshtml.cs | 32 +- 91 files changed, 2474 insertions(+), 406 deletions(-) create mode 100644 modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.Designer.cs create mode 100644 modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.cs create mode 100644 modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/GetPdfFilesInput.cs create mode 100644 modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectPdfFileDto.cs create mode 100644 modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml create mode 100644 modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml.cs create mode 100644 modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js rename modules/docs/src/{Volo.Docs.Web => Volo.Docs.Domain.Shared/Volo/Docs}/HtmlConverting/DocumentToHtmlConverterFactory.cs (82%) create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterOptions.cs create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverter.cs create mode 100644 modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverterFactory.cs delete mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs delete mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs delete mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/DocsDocumentPdfContainer.cs => Projects/Pdf/DocsProjectPdfContainer.cs} (51%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs => Projects/Pdf/DocsProjectPdfGeneratorOptions.cs} (94%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/IDocumentPdfFileStore.cs => Projects/Pdf/IProjectPdfFileStore.cs} (69%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/IDocumentPdfGenerator.cs => Projects/Pdf/IProjectPdfGenerator.cs} (61%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents => Projects}/Pdf/IText/HtmlIdTagWorkerFactory.cs (86%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/IText/ITextPdfRenderer.cs => Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs} (62%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/Markdig => Projects/Pdf/Markdown}/AnchorLinkRenderer.cs (82%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/Markdig => Projects/Pdf/Markdown}/AnchorLinkResolverExtension.cs (64%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/MarkdigPdfDocumentToHtmlConverter.cs rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/PdfDocumentNode.cs => Projects/Pdf/PdfDocument.cs} (71%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/{Documents/Pdf/DocumentPdfGenerator.cs => Projects/Pdf/ProjectPdfGenerator.cs} (52%) create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/ProjectPdfFile.cs create mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterContext.cs delete mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterOptions.cs delete mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs delete mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverterFactory.cs diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.Designer.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.Designer.cs new file mode 100644 index 0000000000..c284a80f8b --- /dev/null +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.Designer.cs @@ -0,0 +1,1376 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using VoloDocs.EntityFrameworkCore; + +#nullable disable + +namespace Migrations +{ + [DbContext(typeof(VoloDocsDbContext))] + [Migration("20250425082043_add_pdf_file")] + partial class add_pdf_file + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("ProductVersion", "9.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("LastAccessed") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SignedIn") + .HasColumnType("datetime2"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("bit") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[TenantId] IS NOT NULL"); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("bit"); + + b.Property("IsInherited") + .HasColumnType("bit"); + + b.Property("IsVisibleToClients") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpSettingDefinitions", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Documents.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("EditLink") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Format") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LanguageCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LastCachedTime") + .HasColumnType("datetime2"); + + b.Property("LastSignificantUpdateTime") + .HasColumnType("datetime2"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetime2"); + + b.Property("LocalDirectory") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("RawRootUrl") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("RootUrl") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("Version") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("DocsDocuments", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Documents.DocumentContributor", b => + { + b.Property("DocumentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Username") + .HasColumnType("nvarchar(450)"); + + b.Property("AvatarUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("CommitCount") + .HasColumnType("int"); + + b.Property("UserProfileUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("DocumentId", "Username"); + + b.ToTable("DocsDocumentContributors", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("DocumentStoreType") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Format") + .HasColumnType("nvarchar(max)"); + + b.Property("LatestVersionBranchName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("MainWebsiteUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("MinimumVersion") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("NavigationDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParametersDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ShortName") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.ToTable("DocsProjects", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("FileName") + .HasColumnType("nvarchar(450)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("LanguageCode") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("Version") + .HasColumnType("nvarchar(max)"); + + b.HasKey("ProjectId", "FileName"); + + b.ToTable("DocsProjectPdfFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Docs.Documents.DocumentContributor", b => + { + b.HasOne("Volo.Docs.Documents.Document", null) + .WithMany("Contributors") + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.HasOne("Volo.Docs.Projects.Project", null) + .WithMany("PdfFiles") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Docs.Documents.Document", b => + { + b.Navigation("Contributors"); + }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Navigation("PdfFiles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.cs new file mode 100644 index 0000000000..2f9f296c25 --- /dev/null +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Migrations +{ + /// + public partial class add_pdf_file : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DocsProjectPdfFiles", + columns: table => new + { + ProjectId = table.Column(type: "uniqueidentifier", nullable: false), + FileName = table.Column(type: "nvarchar(450)", nullable: false), + Version = table.Column(type: "nvarchar(max)", nullable: true), + LanguageCode = table.Column(type: "nvarchar(max)", nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + LastModificationTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DocsProjectPdfFiles", x => new { x.ProjectId, x.FileName }); + table.ForeignKey( + name: "FK_DocsProjectPdfFiles_DocsProjects_ProjectId", + column: x => x.ProjectId, + principalTable: "DocsProjects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DocsProjectPdfFiles"); + } + } +} diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs index 43a60ece76..14f36cafb1 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs @@ -1193,6 +1193,33 @@ namespace Migrations b.ToTable("DocsProjects", (string)null); }); + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("FileName") + .HasColumnType("nvarchar(450)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("LanguageCode") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("Version") + .HasColumnType("nvarchar(max)"); + + b.HasKey("ProjectId", "FileName"); + + b.ToTable("DocsProjectPdfFiles", (string)null); + }); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => { b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) @@ -1299,6 +1326,15 @@ namespace Migrations .IsRequired(); }); + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.HasOne("Volo.Docs.Projects.Project", null) + .WithMany("PdfFiles") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => { b.Navigation("Claims"); @@ -1326,6 +1362,11 @@ namespace Migrations { b.Navigation("Contributors"); }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Navigation("PdfFiles"); + }); #pragma warning restore 612, 618 } } diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index 8702ac6500..f48879b43a 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -39,7 +39,7 @@ using Volo.Abp.Validation.Localization; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Docs.Common.Documents; -using Volo.Docs.Documents.Pdf; +using Volo.Docs.Projects.Pdf; namespace VoloDocs.Web { @@ -175,7 +175,7 @@ namespace VoloDocs.Web options.GoogleSearchEngineId = "77c7266532da1427f"; }); - Configure(options => + Configure(options => { options.BaseUrl = configuration["App:selfUrl"]; options.IndexPagePath = "Index.md"; diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs index 6f9bb6407e..0ce42e3143 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs @@ -14,6 +14,7 @@ namespace Volo.Docs.Admin projects.AddChild(DocsAdminPermissions.Projects.Update, L("Permission:Edit")); projects.AddChild(DocsAdminPermissions.Projects.Delete, L("Permission:Delete")); projects.AddChild(DocsAdminPermissions.Projects.Create, L("Permission:Create")); + projects.AddChild(DocsAdminPermissions.Projects.ManagePdfFiles, L("Permission:ManagePdfFiles")); group.AddPermission(DocsAdminPermissions.Documents.Default, L("Permission:Documents")); } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs index e6043241ea..f5d9a94410 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs @@ -12,6 +12,7 @@ namespace Volo.Docs.Admin public const string Delete = Default + ".Delete"; public const string Update = Default + ".Update"; public const string Create = Default + ".Create"; + public const string ManagePdfFiles = Default + ".ManagePdfFiles"; } public static class Documents diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json index 15cfaaa9d7..bd93067140 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json @@ -63,6 +63,9 @@ "Language": "اللغة", "ForceToGenerateNewPdf": "قوة لتوليد PDF جديد", "PdfGeneratedSuccessfully": "تم توليد PDF بنجاح", - "GenerateAndDownloadPdf": "توليد وتحميل PDF" + "GenerateAndDownloadPdf": "توليد وتحميل PDF", + "PdfFileDeletionWarningMessage": "هل أنت متأكد أنك تريد حذف ملف PDF \"{0}\"?", + "ManagePdfFiles": "إدارة ملفات PDF", + "Permission:ManagePdfFiles": "إدارة ملفات PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json index 63fc1344e0..9543166ac4 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json @@ -63,6 +63,9 @@ "Language": "Jazyk", "ForceToGenerateNewPdf": "Vynutit generování nového PDF", "PdfGeneratedSuccessfully": "PDF generován úspěšně", - "GenerateAndDownloadPdf": "Generovat a stáhnout PDF" + "GenerateAndDownloadPdf": "Generovat a stáhnout PDF", + "PdfFileDeletionWarningMessage": "Opravdu chcete odstranit soubor PDF \"{0}\"?", + "ManagePdfFiles": "Správa PDF souborů", + "Permission:ManagePdfFiles": "Správa PDF souborů" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json index 907fc8236b..a69c9283ea 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json @@ -62,6 +62,9 @@ "Language": "Sprache", "ForceToGenerateNewPdf": "Neues PDF erzwingen", "PdfGeneratedSuccessfully": "PDF erfolgreich generiert", - "GenerateAndDownloadPdf": "PDF generieren und herunterladen" + "GenerateAndDownloadPdf": "PDF generieren und herunterladen", + "PdfFileDeletionWarningMessage": "Sind Sie sicher, dass Sie das PDF-Datei \"{0}\" löschen wollen?", + "ManagePdfFiles": "PDF-Dateien verwalten", + "Permission:ManagePdfFiles": "PDF-Dateien verwalten" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json index 7ec5d5122b..1278047f50 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json @@ -63,6 +63,9 @@ "Language": "Sprache", "ForceToGenerateNewPdf": "Neues PDF erzwingen", "PdfGeneratedSuccessfully": "PDF erfolgreich generiert", - "GenerateAndDownloadPdf": "PDF generieren und herunterladen" + "GenerateAndDownloadPdf": "PDF generieren und herunterladen", + "PdfFileDeletionWarningMessage": "Sind Sie sicher, dass Sie das PDF-Datei \"{0}\" löschen wollen?", + "ManagePdfFiles": "PDF-Dateien verwalten", + "Permission:ManagePdfFiles": "PDF-Dateien verwalten" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json index 75d9bb8122..ae8108dfb5 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json @@ -62,6 +62,9 @@ "Language": "Γλώσσα", "ForceToGenerateNewPdf": "Βάλτε το νέο PDF", "PdfGeneratedSuccessfully": "Το PDF αναπροσαρμοστεί εκ νέου", - "GenerateAndDownloadPdf": "Δημιουργία και λήψη PDF" + "GenerateAndDownloadPdf": "Δημιουργία και λήψη PDF", + "PdfFileDeletionWarningMessage": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το PDF αρχείο \"{0}\";", + "ManagePdfFiles": "Διαχείρηση PDF αρχείων", + "Permission:ManagePdfFiles": "Διαχείρηση PDF αρχείων" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json index de69b69e16..6ed2bb94cd 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json @@ -62,6 +62,9 @@ "Language": "Language", "ForceToGenerateNewPdf": "Force to generate new PDF", "PdfGeneratedSuccessfully": "PDF generated successfully", - "GenerateAndDownloadPdf": "Generate and download PDF" + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json index a0dee2cdd1..bc606f7df7 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json @@ -63,6 +63,9 @@ "Language": "Language", "ForceToGenerateNewPdf": "Force to generate new PDF", "PdfGeneratedSuccessfully": "PDF generated successfully", - "GenerateAndDownloadPdf": "Generate and download PDF" + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json index 9530f8504c..79937b772d 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json @@ -63,6 +63,9 @@ "Language": "Idioma", "ForceToGenerateNewPdf": "Forzar a generar un nuevo PDF", "PdfGeneratedSuccessfully": "PDF generado correctamente", - "GenerateAndDownloadPdf": "Generar y descargar PDF" + "GenerateAndDownloadPdf": "Generar y descargar PDF", + "PdfFileDeletionWarningMessage": "¿Está seguro de querer eliminar el archivo PDF \"{0}\"?", + "ManagePdfFiles": "Administrar archivos PDF", + "Permission:ManagePdfFiles": "Administrar archivos PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json index c1122140c2..d227037f32 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json @@ -63,6 +63,9 @@ "Language": "Kieli", "ForceToGenerateNewPdf": "Vahvista uusi PDF", "PdfGeneratedSuccessfully": "PDF generoidaan onnistuneesti", - "GenerateAndDownloadPdf": "Generoi ja lataa PDF" + "GenerateAndDownloadPdf": "Generoi ja lataa PDF", + "PdfFileDeletionWarningMessage": "Oletko varma, että haluat poistaa PDF-tiedoston \"{0}\"?", + "ManagePdfFiles": "Hallitse PDF-tiedostoja", + "Permission:ManagePdfFiles": "Hallitse PDF-tiedostoja" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json index 98207b1a6a..6efe4fe888 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json @@ -63,6 +63,9 @@ "Language": "Langue", "ForceToGenerateNewPdf": "Forcer à générer un nouveau PDF", "PdfGeneratedSuccessfully": "PDF généré avec succès", - "GenerateAndDownloadPdf": "Générer et télécharger PDF" + "GenerateAndDownloadPdf": "Générer et télécharger PDF", + "PdfFileDeletionWarningMessage": "Êtes-vous sûr de vouloir supprimer le fichier PDF \"{0}\"?", + "ManagePdfFiles": "Gérer les fichiers PDF", + "Permission:ManagePdfFiles": "Gérer les fichiers PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json index d55ba7fb9b..cdca790f20 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json @@ -63,6 +63,9 @@ "Language": "भाषा", "ForceToGenerateNewPdf": "नया PDF उत्पन्न करें", "PdfGeneratedSuccessfully": "PDF सफलतापूर्वक उत्पन्न हो गया", - "GenerateAndDownloadPdf": "PDF उत्पन्न और डाउनलोड करें" + "GenerateAndDownloadPdf": "PDF उत्पन्न और डाउनलोड करें", + "PdfFileDeletionWarningMessage": "क्या आप वाकई \"{0}\" के PDF फ़ाइल को हटाना चाहते हैं?", + "ManagePdfFiles": "PDF फ़ाइलें प्रबंधित करें", + "Permission:ManagePdfFiles": "PDF फ़ाइलें प्रबंधित करें" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json index 6890839ee2..547484a062 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json @@ -63,6 +63,9 @@ "Language": "Jezik", "ForceToGenerateNewPdf": "Prisili generiranje novog PDF-a", "PdfGeneratedSuccessfully": "PDF generiran uspješno", - "GenerateAndDownloadPdf": "Generiraj i preuzmi PDF" + "GenerateAndDownloadPdf": "Generiraj i preuzmi PDF", + "PdfFileDeletionWarningMessage": "Jeste li sigurni da želite izbrisati PDF datoteku \"{0}\"?", + "ManagePdfFiles": "Upravljanje PDF datotekama", + "Permission:ManagePdfFiles": "Upravljanje PDF datotekama" } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json index 15a51e404d..581910f9e9 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json @@ -64,6 +64,9 @@ "Language": "Nyelv", "ForceToGenerateNewPdf": "Új PDF generálása", "PdfGeneratedSuccessfully": "PDF generálás sikeres", - "GenerateAndDownloadPdf": "Generálás és letöltés PDF-ben" + "GenerateAndDownloadPdf": "Generálás és letöltés PDF-ben", + "PdfFileDeletionWarningMessage": "Biztosan törölni szeretné a \"{0}\" PDF fájlt?", + "ManagePdfFiles": "PDF fájlok kezelése", + "Permission:ManagePdfFiles": "PDF fájlok kezelése" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json index aed161fa90..64b41ce3b7 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json @@ -63,6 +63,9 @@ "Language": "Language", "ForceToGenerateNewPdf": "Force to generate new PDF", "PdfGeneratedSuccessfully": "PDF generated successfully", - "GenerateAndDownloadPdf": "Generate and download PDF" + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json index 8b5aaf071e..29e7d1ba80 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json @@ -63,6 +63,9 @@ "Language": "Lingua", "ForceToGenerateNewPdf": "Forza a generare un nuovo PDF", "PdfGeneratedSuccessfully": "PDF generato con successo", - "GenerateAndDownloadPdf": "Genera e scarica PDF" + "GenerateAndDownloadPdf": "Genera e scarica PDF", + "PdfFileDeletionWarningMessage": "Sei sicuro di voler eliminare il file PDF \"{0}\"?", + "ManagePdfFiles": "Gestione file PDF", + "Permission:ManagePdfFiles": "Gestione file PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json index 8ce0777171..6f43a26ac8 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json @@ -63,6 +63,9 @@ "Language": "Taal", "ForceToGenerateNewPdf": "Forceer nieuwe PDF te genereren", "PdfGeneratedSuccessfully": "PDF succesvol gegenereerd", - "GenerateAndDownloadPdf": "PDF genereren en downloaden" + "GenerateAndDownloadPdf": "PDF genereren en downloaden", + "PdfFileDeletionWarningMessage": "Weet u zeker dat u het PDF-bestand \"{0}\" wilt verwijderen?", + "ManagePdfFiles": "PDF-bestanden beheren", + "Permission:ManagePdfFiles": "PDF-bestanden beheren" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json index 785588c3fe..a93ee2bd0f 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json @@ -63,6 +63,9 @@ "Language": "Język", "ForceToGenerateNewPdf": "Wymuś generowanie nowego PDF", "PdfGeneratedSuccessfully": "PDF został pomyślnie wygenerowany", - "GenerateAndDownloadPdf": "Generuj i pobierz PDF" + "GenerateAndDownloadPdf": "Generuj i pobierz PDF", + "PdfFileDeletionWarningMessage": "Czy na pewno chcesz usunąć plik PDF \"{0}\"?", + "ManagePdfFiles": "Zarządzanie plikami PDF", + "Permission:ManagePdfFiles": "Zarządzanie plikami PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json index 59f5006b76..ff8be45830 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json @@ -63,6 +63,9 @@ "Language": "Idioma", "ForceToGenerateNewPdf": "Forçar para gerar um novo PDF", "PdfGeneratedSuccessfully": "PDF gerado com sucesso", - "GenerateAndDownloadPdf": "Gerar e baixar PDF" + "GenerateAndDownloadPdf": "Gerar e baixar PDF", + "PdfFileDeletionWarningMessage": "Tem certeza de que deseja excluir o arquivo PDF \"{0}\"?", + "ManagePdfFiles": "Gerenciar arquivos PDF", + "Permission:ManagePdfFiles": "Gerenciar arquivos PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json index 315b220454..68f40183d8 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json @@ -63,6 +63,9 @@ "Language": "Limba", "ForceToGenerateNewPdf": "Forțați generarea unui nou PDF", "PdfGeneratedSuccessfully": "PDF generat cu succes", - "GenerateAndDownloadPdf": "Generare și descărcare PDF" + "GenerateAndDownloadPdf": "Generare și descărcare PDF", + "PdfFileDeletionWarningMessage": "Sunteți sigur(ă) că doriți să ștergeți fișierul PDF \"{0}\"?", + "ManagePdfFiles": "Gestionare fișiere PDF", + "Permission:ManagePdfFiles": "Gestionare fișiere PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json index 59ad3ad1cc..bc2691121d 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json @@ -63,6 +63,9 @@ "Language": "Язык", "ForceToGenerateNewPdf": "Принудительное создание нового PDF", "PdfGeneratedSuccessfully": "PDF успешно сгенерирован", - "GenerateAndDownloadPdf": "Сгенерировать и скачать PDF" + "GenerateAndDownloadPdf": "Сгенерировать и скачать PDF", + "PdfFileDeletionWarningMessage": "Вы уверены, что хотите удалить файл PDF \"{0}\"?", + "ManagePdfFiles": "Управление файлами PDF", + "Permission:ManagePdfFiles": "Управление файлами PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json index 62e57ccc4c..8b06da0e82 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json @@ -63,6 +63,9 @@ "Language": "Jazyk", "ForceToGenerateNewPdf": "Vynútiť generovanie nového PDF", "PdfGeneratedSuccessfully": "PDF generovaný úspešne", - "GenerateAndDownloadPdf": "Generovať a stiahnuť PDF" + "GenerateAndDownloadPdf": "Generovať a stiahnuť PDF", + "PdfFileDeletionWarningMessage": "Ste si istý, že chcete odstrániť súbor PDF \"{0}\"?", + "ManagePdfFiles": "Správa PDF súborov", + "Permission:ManagePdfFiles": "Správa PDF súborov" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json index 904df440bd..0fe64f8903 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json @@ -63,6 +63,9 @@ "Language": "Jezik", "ForceToGenerateNewPdf": "Prisili generiranje novega PDF", "PdfGeneratedSuccessfully": "PDF generiran uspešno", - "GenerateAndDownloadPdf": "Generiraj in prenesi PDF" + "GenerateAndDownloadPdf": "Generiraj in prenesi PDF", + "PdfFileDeletionWarningMessage": "Ali ste prepričani, da želite izbrisati datoteko PDF »{0}«?", + "ManagePdfFiles": "Upravljanje datotek PDF", + "Permission:ManagePdfFiles": "Upravljanje datotek PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json index 694fb74c9c..db67ecb79b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json @@ -63,6 +63,9 @@ "Language": "Språk", "ForceToGenerateNewPdf": "Force to generate new PDF", "PdfGeneratedSuccessfully": "PDF generated successfully", - "GenerateAndDownloadPdf": "Generate and download PDF" + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json index aece0ba3e8..42283a4b89 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json @@ -63,6 +63,9 @@ "Language": "Dil", "ForceToGenerateNewPdf": "Yeni bir PDF oluştur", "PdfGeneratedSuccessfully": "PDF başarıyla oluşturuldu", - "GenerateAndDownloadPdf": "PDF oluştur ve indir" + "GenerateAndDownloadPdf": "PDF oluştur ve indir", + "PdfFileDeletionWarningMessage": "{0} PDF dosyasını silmek istediğinizden emin misiniz?", + "ManagePdfFiles": "PDF dosyalarını yönet", + "Permission:ManagePdfFiles": "PDF dosyalarını yönet" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json index b6e68b8bf6..176b427e59 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json @@ -63,6 +63,9 @@ "Language": "Ngôn ngữ", "ForceToGenerateNewPdf": "Tạo PDF mới", "PdfGeneratedSuccessfully": "PDF đã được tạo thành công", - "GenerateAndDownloadPdf": "Tạo và tải xuống PDF" + "GenerateAndDownloadPdf": "Tạo và tải xuống PDF", + "PdfFileDeletionWarningMessage": "Bạn có chắc chắn muốn xóa tệp PDF \"{0}\" không?", + "ManagePdfFiles": "Quản lý tệp PDF", + "Permission:ManagePdfFiles": "Quản lý tệp PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json index d2273412ad..137e42e4ae 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json @@ -63,6 +63,9 @@ "Language": "语言", "ForceToGenerateNewPdf": "强制生成新PDF", "PdfGeneratedSuccessfully": "PDF生成成功", - "GenerateAndDownloadPdf": "生成并下载PDF" + "GenerateAndDownloadPdf": "生成并下载PDF", + "PdfFileDeletionWarningMessage": "你确定要删除PDF文件“{0}”吗?", + "ManagePdfFiles": "管理PDF文件", + "Permission:ManagePdfFiles": "管理PDF文件" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json index 7492a2c462..bfa6e4ea97 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json @@ -63,6 +63,9 @@ "Language": "語言", "ForceToGenerateNewPdf": "强制生成新PDF", "PdfGeneratedSuccessfully": "PDF生成成功", - "GenerateAndDownloadPdf": "生成并下载PDF" + "GenerateAndDownloadPdf": "生成并下载PDF", + "PdfFileDeletionWarningMessage": "你確定要刪除PDF文件“{0}”嗎?", + "ManagePdfFiles": "管理PDF文件", + "Permission:ManagePdfFiles": "管理PDF文件" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/GetPdfFilesInput.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/GetPdfFilesInput.cs new file mode 100644 index 0000000000..f8a371dd57 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/GetPdfFilesInput.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Volo.Docs.Admin.Projects; + +public class GetPdfFilesInput : PagedAndSortedResultRequestDto +{ + public Guid ProjectId { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs index 4503027bed..41b309f308 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs @@ -23,6 +23,8 @@ namespace Volo.Docs.Admin.Projects Task ReindexAllAsync(); Task> GetListWithoutDetailsAsync(); + Task> GetPdfFilesAsync(GetPdfFilesInput input); + Task DeletePdfFileAsync(DeletePdfFileInput input); } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectPdfFileDto.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectPdfFileDto.cs new file mode 100644 index 0000000000..4f2d012475 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectPdfFileDto.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Docs.Admin.Projects; + +[Serializable] +public class ProjectPdfFileDto +{ + public virtual Guid ProjectId { get; set; } + public virtual string FileName { get; set; } + public virtual string Version { get; set; } + public virtual string LanguageCode { get; set; } + public virtual DateTime CreationTime { get; set; } + public virtual DateTime? LastModificationTime { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs index 01a7250ce5..366c0ab27b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs @@ -16,6 +16,7 @@ namespace Volo.Docs.Admin CreateMap(); CreateMap(); CreateMap(); + CreateMap(); } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs index a5d61aa358..0c06fb23a8 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs @@ -3,17 +3,16 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; -using Volo.Abp.Caching; using Volo.Abp.Data; using Volo.Abp.Guids; -using Volo.Docs.Common.Documents; using Volo.Docs.Documents; using Volo.Docs.Documents.FullSearch.Elastic; -using Volo.Docs.Documents.Pdf; using Volo.Docs.Localization; using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf; namespace Volo.Docs.Admin.Projects { @@ -24,14 +23,14 @@ namespace Volo.Docs.Admin.Projects private readonly IDocumentRepository _documentRepository; private readonly IDocumentFullSearch _elasticSearchService; private readonly IGuidGenerator _guidGenerator; - private readonly IDistributedCache _documentPdfCache; + private readonly IOptions _pdfGeneratorOptions; public ProjectAdminAppService( IProjectRepository projectRepository, IDocumentRepository documentRepository, IDocumentFullSearch elasticSearchService, - IGuidGenerator guidGenerator, - IDistributedCache documentPdfCache) + IGuidGenerator guidGenerator, + IOptions pdfGeneratorOptions) { ObjectMapperContext = typeof(DocsAdminApplicationModule); LocalizationResource = typeof(DocsResource); @@ -40,7 +39,7 @@ namespace Volo.Docs.Admin.Projects _documentRepository = documentRepository; _elasticSearchService = elasticSearchService; _guidGenerator = guidGenerator; - _documentPdfCache = documentPdfCache; + _pdfGeneratorOptions = pdfGeneratorOptions; } public virtual async Task> GetListAsync(PagedAndSortedResultRequestDto input) @@ -183,9 +182,26 @@ namespace Volo.Docs.Admin.Projects return ObjectMapper.Map, List>(projects); } + [Authorize(DocsAdminPermissions.Projects.ManagePdfFiles)] + public virtual async Task> GetPdfFilesAsync(GetPdfFilesInput input) + { + var project = await _projectRepository.GetAsync(input.ProjectId, includeDetails: true); + + var pdfFiles = project.PdfFiles.Skip(input.SkipCount).Take(input.MaxResultCount).ToList(); + + return new PagedResultDto( + project.PdfFiles.Count, + ObjectMapper.Map, List>(pdfFiles) + ); + } + + [Authorize(DocsAdminPermissions.Projects.ManagePdfFiles)] public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) { - await _documentPdfCache.RemoveAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(input.ProjectId, input.Version, input.LanguageCode)); + var project = await _projectRepository.GetAsync(input.ProjectId, includeDetails: true); + project.RemovePdfFile(_pdfGeneratorOptions.Value.CalculatePdfFileName(project, input.Version, input.LanguageCode)); + + await _projectRepository.UpdateAsync(project); } } } diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs index baaea015c3..9437ee487d 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/ProjectsAdminClientProxy.Generated.cs @@ -68,6 +68,14 @@ public partial class ProjectsAdminClientProxy : ClientProxyBase>(nameof(GetListWithoutDetailsAsync)); } + public virtual async Task> GetPdfFilesAsync(GetPdfFilesInput input) + { + return await RequestAsync>(nameof(GetPdfFilesAsync), new ClientProxyRequestTypeValue + { + { typeof(GetPdfFilesInput), input } + }); + } + public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) { await RequestAsync(nameof(DeletePdfFileAsync), new ClientProxyRequestTypeValue diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json index 96eddc28ee..636c7b6d25 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json @@ -722,6 +722,23 @@ "typeSimple": "[Volo.Docs.Admin.Projects.ProjectWithoutDetailsDto]" } }, + { + "name": "GetPdfFilesAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.GetPdfFilesInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "typeSimple": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + } + }, { "name": "DeletePdfFileAsync", "parametersOnMethod": [ @@ -1002,6 +1019,79 @@ "allowAnonymous": null, "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" }, + "GetPdfFilesAsyncByInput": { + "uniqueName": "GetPdfFilesAsyncByInput", + "name": "GetPdfFilesAsync", + "httpMethod": "GET", + "url": "api/docs/admin/projects/PdfFiles", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.GetPdfFilesInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "typeSimple": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Sorting", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "SkipCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "MaxResultCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, "DeletePdfFileAsyncByInput": { "uniqueName": "DeletePdfFileAsyncByInput", "name": "DeletePdfFileAsync", diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs index f4ac744f76..e020486887 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs @@ -70,6 +70,13 @@ namespace Volo.Docs.Admin return _projectAppService.GetListWithoutDetailsAsync(); } + [HttpGet] + [Route("PdfFiles")] + public Task> GetPdfFilesAsync(GetPdfFilesInput input) + { + return _projectAppService.GetPdfFilesAsync(input); + } + [HttpDelete] [Route("DeletePdfFile")] public Task DeletePdfFileAsync(DeletePdfFileInput input) diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml index 7eda48cf29..b8ad9742d8 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml @@ -41,7 +41,7 @@ - + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml index b80d2d76db..1bdbf7467e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml @@ -25,6 +25,7 @@ + } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml new file mode 100644 index 0000000000..de1034112e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml @@ -0,0 +1,41 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Docs.Localization +@model Volo.Docs.Admin.Pages.Docs.Admin.Projects.ManagePdfFiles +@inject IHtmlLocalizer L + +@{ + Layout = null; +} + + + + + + + + + + + + + + + + + @L["Actions"] + @L["FileName"] + @L["Version"] + @L["LanguageCode"] + @L["CreationTime"] + @L["LastUpdateTime"] + + + + + + + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml.cs b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml.cs new file mode 100644 index 0000000000..bb5218419b --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Docs.Admin.Pages.Docs.Admin.Projects; + +[Authorize(DocsAdminPermissions.Projects.Default)] +public class ManagePdfFiles : DocsAdminPageModel +{ + public virtual Task OnGet() + { + return Task.FromResult(Page()); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js index e65f978690..7b7f4b1bbf 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js @@ -1,7 +1,8 @@ var abp = abp || {}; $(function () { abp.modals.projectGeneratePdf = function () { - + + var l = abp.localization.getResource('Docs'); var projectAppService = volo.docs.projects.docsProject; var pdfGeneratorAppService = volo.docs.documents.docsDocumentPdfGenerator; var projectAdminAppService = volo.docs.admin.projectsAdmin; @@ -21,7 +22,7 @@ $(function () { }); }) - $("#GeneratePdfBtn").click(function () { + $("#GenerateBtn").click(function () { var $btn = $(this); $btn.buttonBusy(true); $("#GenerateAndDownloadPdfBtn").buttonBusy(true); @@ -30,19 +31,28 @@ $(function () { version: $("#Version").val(), languageCode: $("#Language").val(), } - tryDeletePdfFile(input); - pdfGeneratorAppService.generatePdf(input, { - abpHandleError : false, - error: function (jqXHR) { - if (jqXHR.status === 200) { - abp.message.success("PDF generated successfully."); - $btn.buttonBusy(false); - $("#GenerateAndDownloadPdfBtn").buttonBusy(false); - } else { - abp.ajax.handleErrorStatusCode(jqXHR.status); + + function generatePdf(input) { + pdfGeneratorAppService.generatePdf(input, { + abpHandleError : false, + error: function (jqXHR) { + if (jqXHR.status === 200) { + abp.message.success(l('PdfFileDeletedSuccessfully')); + $btn.buttonBusy(false); + $("#GenerateAndDownloadPdfBtn").buttonBusy(false); + } else { + abp.ajax.handleErrorStatusCode(jqXHR.status); + } } - } - }); + }); + } + if(shouldForceToGenerate(input)){ + projectAdminAppService.deletePdfFile(input).done(() =>{ + generatePdf(input); + }); + }else{ + generatePdf(input); + } }) $("#GenerateAndDownloadPdfBtn").click(function () { @@ -51,15 +61,17 @@ $(function () { version: $("#Version").val(), languageCode: $("#Language").val(), } - tryDeletePdfFile(input); - window.open(abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]), '_blank'); + if(shouldForceToGenerate(input)){ + projectAdminAppService.deletePdfFile(input).done(() =>{ + window.open(abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]), '_blank'); + }); + }else{ + window.open(abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]), '_blank'); + } }) - function tryDeletePdfFile(input) { - var forceToGenerate = $("#ForceToGenerate").is(":checked"); - if(forceToGenerate) { - projectAdminAppService.deletePdfFile(input); - } + function shouldForceToGenerate(input) { + return $("#ForceToGenerate").is(":checked"); } return { diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js index a362435088..a367cda36e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js @@ -16,9 +16,9 @@ $(function () { modalClass: 'projectPull', }); - var _generatePdfModal = new abp.ModalManager({ - viewUrl: abp.appPath + 'Docs/Admin/Projects/GeneratePdf', - modalClass: 'projectGeneratePdf', + var _managePdfFilesModal = new abp.ModalManager({ + viewUrl: abp.appPath + 'Docs/Admin/Projects/ManagePdfFiles', + modalClass: 'projectManagePdfFiles', }); var _dataTable = $('#ProjectsTable').DataTable( @@ -123,13 +123,13 @@ $(function () { }, }, { - text: l('GeneratePdf'), + text: l('ManagePdfFiles'), visible: abp.auth.isGranted( 'Docs.Admin.Documents' ), action: function (data) { - _generatePdfModal.open({ - Id: data.record.id, + _managePdfFilesModal.open({ + projectId: data.record.id, }); } } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js new file mode 100644 index 0000000000..72a7aaa1ee --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js @@ -0,0 +1,94 @@ +var abp = abp || {}; +$(function () { + abp.modals.projectManagePdfFiles = function () { + + var l = abp.localization.getResource('Docs'); + var projectAdminAppService = volo.docs.admin.projectsAdmin; + + var _generatePdfModal = new abp.ModalManager({ + viewUrl: abp.appPath + 'Docs/Admin/Projects/GeneratePdf', + modalClass: 'projectGeneratePdf', + }); + + var initModal = function (publicApi, args) { + var _dataTable = $('#ProjectPdfFilesTable').DataTable( + abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + scrollX: true, + paging: true, + searching: false, + autoWidth: false, + scrollCollapse: true, + order: [[2, 'desc']], + ajax: abp.libs.datatables.createAjax( + volo.docs.admin.projectsAdmin.getPdfFiles, + { + projectId : args.projectId + } + ), + columnDefs: [ + { + rowAction: { + items: [ + { + text: l('Delete'), + confirmMessage: function (data) { + return l('PdfFileDeletionWarningMessage', { fileName: data.record.fileName }); + }, + action: function (data) { + projectAdminAppService.deletePdfFile({ + projectId: data.record.projectId, + version: data.record.version, + languageCode: data.record.languageCode + }).then(() => { + _dataTable.ajax.reloadEx(); + abp.notify.success(l('PdfGeneratedSuccessfully')); + }) + }, + } + ], + }, + }, + { + target: 1, + data: 'fileName', + }, + { + target: 2, + data: 'version', + }, + { + target: 3, + data: 'languageCode', + }, + { + target: 4, + data: `creationTime`, + dataFormat: "datetime" + }, + { + target: 5, + data: `lastModificationTime`, + dataFormat: "datetime" + } + ], + }) + ); + + $('#GeneratePdfBtn').click(function () { + _generatePdfModal.open({ + Id: args.projectId, + }); + }); + + _generatePdfModal.onClose(function () { + _dataTable.ajax.reloadEx(); + }); + }; + + return { + initModal: initModal, + }; + }; +}); diff --git a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js index 60bab5146a..a1e2aafaca 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js @@ -136,6 +136,13 @@ }, ajaxParams)); }; + volo.docs.admin.projectsAdmin.getPdfFiles = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/admin/projects/PdfFiles' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', + type: 'GET' + }, ajaxParams)); + }; + volo.docs.admin.projectsAdmin.deletePdfFile = function(input, ajaxParams) { return abp.ajax($.extend(true, { url: abp.appPath + 'api/docs/admin/projects/DeletePdfFile' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', 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 index 16f3597152..0bdfc7fa1d 100644 --- 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 @@ -10,7 +10,7 @@ namespace Volo.Docs.Common { var group = context.AddGroup(DocsCommonPermissions.GroupName, L("Permission:DocumentManagement.Common")); - group.AddPermission(DocsCommonPermissions.Documents.PdfGeneration, L("Permission:PdfGeneration")); + group.AddPermission(DocsCommonPermissions.Projects.PdfGeneration, L("Permission:PdfGeneration")); } private static LocalizableString L(string 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 index 4d2d2a3827..f668f00813 100644 --- 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 @@ -6,7 +6,7 @@ namespace Volo.Docs.Common { public const string GroupName = "Docs.Common"; - public static class Documents + public static class Projects { public const string PdfGeneration = GroupName + ".PdfGeneration"; } 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 index c51f9366b3..7787185b50 100644 --- 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 @@ -1,30 +1,29 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Services; -using Volo.Abp.BlobStoring; using Volo.Abp.Content; -using Volo.Docs.Documents.Pdf; using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf; namespace Volo.Docs.Common.Documents; -[Authorize(DocsCommonPermissions.Documents.PdfGeneration)] +[Authorize(DocsCommonPermissions.Projects.PdfGeneration)] public class DocumentPdfGeneratorAppService : ApplicationService, IDocumentPdfGeneratorAppService { - protected IDocumentPdfGenerator DocumentPdfGenerator { get; } + protected IProjectPdfGenerator ProjectPdfGenerator { get; } protected IProjectRepository ProjectRepository { get; } public DocumentPdfGeneratorAppService( - IDocumentPdfGenerator documentPdfGenerator, + IProjectPdfGenerator projectPdfGenerator, IProjectRepository projectRepository) { - DocumentPdfGenerator = documentPdfGenerator; + ProjectPdfGenerator = projectPdfGenerator; ProjectRepository = projectRepository; } public virtual async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) { - var project = await ProjectRepository.GetAsync(input.ProjectId); - return await DocumentPdfGenerator.GenerateAsync(project, input.Version, input.LanguageCode); + var project = await ProjectRepository.GetAsync(input.ProjectId, includeDetails: true); + return await ProjectPdfGenerator.GenerateAsync(project, input.Version, input.LanguageCode); } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs index ae116b850f..0bcdfdb8d1 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs @@ -5,7 +5,7 @@ namespace Volo.Docs.Documents; public class DocumentParams { - [JsonPropertyName("Parameters")] + [JsonPropertyName("parameters")] public List Parameters { get; set; } = new(); @@ -18,6 +18,6 @@ public class DocumentParams public string DisplayName { get; set; } [JsonPropertyName("values")] - public List> Values { get; set; } + public Dictionary Values { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterFactory.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterFactory.cs similarity index 82% rename from modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterFactory.cs rename to modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterFactory.cs index a6a7978eee..43a239b297 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterFactory.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterFactory.cs @@ -19,7 +19,7 @@ namespace Volo.Docs.HtmlConverting Options = options.Value; } - public virtual IDocumentToHtmlConverter Create(string format) + public virtual IDocumentToHtmlConverter Create(string format) { var serviceType = Options.Converters.GetOrDefault(format); if (serviceType == null) @@ -27,7 +27,7 @@ namespace Volo.Docs.HtmlConverting throw new ApplicationException($"Unknown document format: {format}"); } - return (IDocumentToHtmlConverter)ServiceProvider.GetRequiredService(serviceType); + return (IDocumentToHtmlConverter)ServiceProvider.GetRequiredService(serviceType); } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterOptions.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterOptions.cs new file mode 100644 index 0000000000..a658140d08 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterOptions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Docs.HtmlConverting; + +public class DocumentToHtmlConverterOptions +{ + public Dictionary Converters { get; set; } + + public DocumentToHtmlConverterOptions() + { + Converters = new Dictionary(); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverter.cs new file mode 100644 index 0000000000..351e34feba --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverter.cs @@ -0,0 +1,9 @@ +using Volo.Docs.Documents; +using Volo.Docs.HtmlConverting; + +namespace Volo.Docs.HtmlConverting; + +public interface IDocumentToHtmlConverter +{ + string Convert(TContext context); +} diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverterFactory.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverterFactory.cs new file mode 100644 index 0000000000..0be9f79187 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverterFactory.cs @@ -0,0 +1,6 @@ +namespace Volo.Docs.HtmlConverting; + +public interface IDocumentToHtmlConverterFactory +{ + IDocumentToHtmlConverter Create(string format); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs index ff6bd56ee4..1e8463fe6c 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs @@ -3,5 +3,6 @@ public class DocsDomainConsts { public static string LanguageConfigFileName = "docs-langs.json"; + public static string PdfDocumentToHtmlConverterPrefix = "pdf-"; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs index c9fb4cb6f7..b4f6927ce0 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs @@ -17,8 +17,11 @@ using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Docs.FileSystem.Documents; using Volo.Docs.GitHub; using Volo.Docs.GitHub.Documents; +using Volo.Docs.HtmlConverting; using Volo.Docs.Localization; using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf.Markdig; +using Volo.Docs.Projects.Pdf.Markdown; namespace Volo.Docs { @@ -79,6 +82,11 @@ namespace Volo.Docs { client.Timeout = TimeSpan.FromMilliseconds(15000); }); + + Configure(options => + { + options.Converters[DocsDomainConsts.PdfDocumentToHtmlConverterPrefix + MarkdigPdfDocumentToHtmlConverter.Type] = typeof(MarkdigPdfDocumentToHtmlConverter); + }); } public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs deleted file mode 100644 index 1415bf73f0..0000000000 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/BlobDocumentPdfFileStore.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Options; -using Volo.Abp.BlobStoring; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Docs.Projects; - -namespace Volo.Docs.Documents.Pdf; - -public class BlobDocumentPdfFileStore : IDocumentPdfFileStore, ITransientDependency -{ - protected IBlobContainer BlobContainer { get; } - protected IDistributedCache Cache { get; } - protected IOptions Options { get; } - - public BlobDocumentPdfFileStore( - IBlobContainer blobContainer, - IDistributedCache cache, - IOptions options) - { - BlobContainer = blobContainer; - Cache = cache; - Options = options; - } - - public virtual async Task SetAsync(Project project, string version, string languageCode, Stream stream) - { - await BlobContainer.SaveAsync(Options.Value.CalculatePdfFileName(project, version, languageCode), stream, true); - - await Cache.SetAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(project.Id, version, languageCode), new DocsDocumentPdfCacheItem(), - new DistributedCacheEntryOptions - { - AbsoluteExpiration = DateTimeOffset.Now.Add(Options.Value.PdfFileCacheExpiration) - }); - } - - public virtual async Task GetOrNullAsync(Project project, string version, string languageCode) - { - var cache = await Cache.GetAsync(DocsDocumentPdfCacheItem.CalculateCacheKey(project.Id, version, languageCode)); - if (cache == null) - { - return null; - } - - return await BlobContainer.GetOrNullAsync(Options.Value.CalculatePdfFileName(project, version, languageCode)); - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs deleted file mode 100644 index 3763446e83..0000000000 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfCacheItem.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Volo.Docs.Documents.Pdf; - -public class DocsDocumentPdfCacheItem -{ - public static string CalculateCacheKey(Guid projectId, string version, string languageCode) - { - return $"{projectId}_{version}_{languageCode}"; - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs deleted file mode 100644 index cb950c8b7b..0000000000 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IPdfRenderer.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace Volo.Docs.Documents.Pdf; - -public interface IPdfRenderer -{ - Task GeneratePdfAsync(string htmlContent, List pdfDocumentNodes); -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs index db13ea2c8a..9d7443c5b2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs @@ -8,7 +8,7 @@ namespace Volo.Docs.Projects { public interface IProjectRepository : IBasicRepository { - Task> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default); + Task> GetListAsync(string sorting, int maxResultCount, int skipCount,bool includeDetails = false, CancellationToken cancellationToken = default); Task> GetListWithoutDetailsAsync(CancellationToken cancellationToken = default); Task GetByShortNameAsync(string shortName, CancellationToken cancellationToken = default); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs new file mode 100644 index 0000000000..8f3cca16aa --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs @@ -0,0 +1,64 @@ +using System.IO; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.BlobStoring; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Timing; + +namespace Volo.Docs.Projects.Pdf; + +public class BlobProjectPdfFileStore : IProjectPdfFileStore, ITransientDependency +{ + protected IBlobContainer BlobContainer { get; } + protected IOptions Options { get; } + protected IProjectRepository ProjectRepository { get; } + protected IClock Clock { get; } + + public BlobProjectPdfFileStore( + IBlobContainer blobContainer, + IOptions options, + IClock clock, IProjectRepository projectRepository) + { + BlobContainer = blobContainer; + Options = options; + Clock = clock; + ProjectRepository = projectRepository; + } + + public virtual async Task SetAsync(Project project, string version, string languageCode, Stream stream) + { + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + await BlobContainer.SaveAsync(fileName, stream, true); + + var pdfFile = project.FindPdfFile(fileName); + if(pdfFile == null) + { + project.AddPdfFile(project.Id, fileName, version, languageCode); + } + else + { + pdfFile.LastModificationTime = Clock.Now; + } + + await ProjectRepository.UpdateAsync(project); + } + + public virtual async Task GetOrNullAsync(Project project, string version, string languageCode) + { + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + + var pdfFile = project.FindPdfFile(fileName); + if (pdfFile == null) + { + return null; + } + + var lastModificationTime = pdfFile.LastModificationTime ?? pdfFile.CreationTime; + if(lastModificationTime.Add(Options.Value.PdfFileCacheExpiration) <= Clock.Now) + { + return null; + } + + return await BlobContainer.GetOrNullAsync(Options.Value.CalculatePdfFileName(project, version, languageCode)); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfContainer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfContainer.cs similarity index 51% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfContainer.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfContainer.cs index 9a6e13f4ba..554ed42601 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfContainer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfContainer.cs @@ -1,9 +1,9 @@ using Volo.Abp.BlobStoring; -namespace Volo.Docs.Documents.Pdf; +namespace Volo.Docs.Projects.Pdf; [BlobContainerName("docs-document-pdf")] -public class DocsDocumentPdfContainer +public class DocsProjectPdfContainer { } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs similarity index 94% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs index cf99c30991..708dd7f94d 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs @@ -1,9 +1,8 @@ using System; -using Volo.Docs.Projects; -namespace Volo.Docs.Documents.Pdf; +namespace Volo.Docs.Projects.Pdf; -public class DocsDocumentPdfGeneratorOptions +public class DocsProjectPdfGeneratorOptions { public const string StylePlaceholder = "{{style-placeholder}}"; public const string ContentPlaceholder = "{{content-placeholder}}"; @@ -41,7 +40,7 @@ public class DocsDocumentPdfGeneratorOptions /// public Func CalculatePdfFileName { get; set; } - public DocsDocumentPdfGeneratorOptions() + public DocsProjectPdfGeneratorOptions() { HtmlLayout = $@" diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs new file mode 100644 index 0000000000..f134b0cdb2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace Volo.Docs.Projects.Pdf; + +public interface IHtmlToPdfRenderer +{ + Task RenderAsync(string html, List documents); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs similarity index 69% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfFileStore.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs index 7cbbc67ee2..2dfc203400 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfFileStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs @@ -1,10 +1,9 @@ using System.IO; using System.Threading.Tasks; -using Volo.Docs.Projects; -namespace Volo.Docs.Documents.Pdf; +namespace Volo.Docs.Projects.Pdf; -public interface IDocumentPdfFileStore +public interface IProjectPdfFileStore { Task SetAsync(Project project, string version, string languageCode, Stream stream); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfGenerator.cs similarity index 61% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfGenerator.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfGenerator.cs index aca44d41be..af685659fa 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IDocumentPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfGenerator.cs @@ -1,10 +1,9 @@ using System.Threading.Tasks; using Volo.Abp.Content; -using Volo.Docs.Projects; -namespace Volo.Docs.Documents.Pdf; +namespace Volo.Docs.Projects.Pdf; -public interface IDocumentPdfGenerator +public interface IProjectPdfGenerator { Task GenerateAsync(Project project, string version, string languageCode); } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/HtmlIdTagWorkerFactory.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/HtmlIdTagWorkerFactory.cs similarity index 86% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/HtmlIdTagWorkerFactory.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/HtmlIdTagWorkerFactory.cs index 4eb9fcda62..17483a7605 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/HtmlIdTagWorkerFactory.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/HtmlIdTagWorkerFactory.cs @@ -1,18 +1,17 @@ using System.Collections.Generic; using iText.Html2pdf.Attach; using iText.Html2pdf.Attach.Impl; -using iText.Kernel.Pdf; using iText.Kernel.Pdf.Navigation; using iText.StyledXmlParser.Node; -namespace Volo.Docs.Documents.Pdf.IText; +namespace Volo.Docs.Projects.Pdf.IText; public class HtmlIdTagWorkerFactory : DefaultTagWorkerFactory { - private readonly PdfDocument _pdfDocument; + private readonly iText.Kernel.Pdf.PdfDocument _pdfDocument; private readonly Dictionary _pageDestinations = new(); - public HtmlIdTagWorkerFactory(PdfDocument pdfDocument) + public HtmlIdTagWorkerFactory(iText.Kernel.Pdf.PdfDocument pdfDocument) { _pdfDocument = pdfDocument; } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs similarity index 62% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs index 2634a34724..9ecc866105 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text; using System.Threading.Tasks; using iText.Html2pdf; using iText.Kernel.Pdf; @@ -10,46 +9,41 @@ using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using ITextDocument = iText.Layout.Document; -namespace Volo.Docs.Documents.Pdf.IText; +namespace Volo.Docs.Projects.Pdf.IText; -public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency +public class ITextHtmlToPdfRenderer : IHtmlToPdfRenderer ,ITransientDependency { - protected IOptions Options { get; } + protected IOptions Options { get; } - public ITextPdfRenderer(IOptions options) + public ITextHtmlToPdfRenderer(IOptions options) { Options = options; } - public virtual async Task GeneratePdfAsync(string htmlContent, List pdfDocumentNodes) + public virtual Task RenderAsync(string html, List documents) { var pdfStream = new MemoryStream(); var pdfWrite = new PdfWriter(pdfStream); - var pdfDocument = new PdfDocument(pdfWrite); + var pdfDocument = new iText.Kernel.Pdf.PdfDocument(pdfWrite); var textDocument = new ITextDocument(pdfDocument); pdfWrite.SetCloseStream(false); - var htmlBuilder = new StringBuilder(); - htmlBuilder.Append(Options.Value.HtmlLayout); - htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyle); - htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.ContentPlaceholder, htmlContent); - var converter = new ConverterProperties(); var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); converter.SetTagWorkerFactory(tagWorkerFactory); - HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter); + HtmlConverter.ConvertToDocument(html, pdfDocument, converter); tagWorkerFactory.AddNamedDestinations(); var pdfOutlines = pdfDocument.GetOutlines(false); - BuildPdfOutlines(pdfOutlines, pdfDocumentNodes); + BuildPdfOutlines(pdfOutlines, documents); textDocument.Close(); pdfStream.Position = 0; - return pdfStream; + return Task.FromResult(pdfStream); } - private void BuildPdfOutlines(PdfOutline parentOutline, List pdfDocumentNodes) + private void BuildPdfOutlines(PdfOutline parentOutline, List pdfDocumentNodes) { foreach (var pdfDocumentNode in pdfDocumentNodes) { diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkRenderer.cs similarity index 82% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkRenderer.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkRenderer.cs index 7f8d65d4ff..33fd2fd83a 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkRenderer.cs @@ -1,22 +1,19 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using Markdig.Renderers; using Markdig.Renderers.Html.Inlines; -using Markdig.Syntax; using Markdig.Syntax.Inlines; using Volo.Docs.Utils; -namespace Volo.Docs.Documents.Pdf.Markdig; +namespace Volo.Docs.Projects.Pdf.Markdig; public class AnchorLinkRenderer : LinkInlineRenderer { - private readonly PdfDocumentNode _documentNode; + private readonly PdfDocument _document; - public AnchorLinkRenderer(PdfDocumentNode documentNode) + public AnchorLinkRenderer(PdfDocument document) { - _documentNode = documentNode; + _document = document; } protected override void Write(HtmlRenderer renderer, LinkInline link) @@ -27,7 +24,7 @@ public class AnchorLinkRenderer : LinkInlineRenderer return; } - var anchor = ResolveRelativeMarkdownPath(_documentNode.Document.Name, link.Url) + var anchor = ResolveRelativeMarkdownPath(_document.Document.Name, link.Url) .Replace(".md",string.Empty).Replace("/","-").Replace(" ", "-").ToLower(); renderer.Write(""); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkResolverExtension.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkResolverExtension.cs similarity index 64% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkResolverExtension.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkResolverExtension.cs index d8a66b368a..38405da4d7 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/Markdig/AnchorLinkResolverExtension.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkResolverExtension.cs @@ -2,15 +2,15 @@ using Markdig; using Markdig.Renderers; using Markdig.Renderers.Html.Inlines; -namespace Volo.Docs.Documents.Pdf.Markdig; +namespace Volo.Docs.Projects.Pdf.Markdig; public class AnchorLinkResolverExtension : IMarkdownExtension { - private readonly PdfDocumentNode _documentNode; + private readonly PdfDocument _document; - public AnchorLinkResolverExtension(PdfDocumentNode documentNode) + public AnchorLinkResolverExtension(PdfDocument document) { - _documentNode = documentNode; + _document = document; } public void Setup(MarkdownPipelineBuilder pipeline) @@ -21,7 +21,7 @@ public class AnchorLinkResolverExtension : IMarkdownExtension { if (renderer is HtmlRenderer htmlRenderer) { - htmlRenderer.ObjectRenderers.Replace(new AnchorLinkRenderer(_documentNode)); + htmlRenderer.ObjectRenderers.Replace(new AnchorLinkRenderer(_document)); } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/MarkdigPdfDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/MarkdigPdfDocumentToHtmlConverter.cs new file mode 100644 index 0000000000..105db5a956 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/MarkdigPdfDocumentToHtmlConverter.cs @@ -0,0 +1,73 @@ +using System; +using System.Text.RegularExpressions; +using System.Web; +using Markdig; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Docs.HtmlConverting; +using Volo.Docs.Projects.Pdf.Markdig; +using Volo.Docs.Utils; + +namespace Volo.Docs.Projects.Pdf.Markdown; + +public class MarkdigPdfDocumentToHtmlConverter : IDocumentToHtmlConverter, ITransientDependency +{ + public const string Type = "md"; + protected IOptions Options { get; } + + public MarkdigPdfDocumentToHtmlConverter(IOptions options) + { + Options = options; + } + + public virtual string Convert(PdfDocumentToHtmlConverterContext converterContext) + { + var htmlContent = global::Markdig.Markdown.ToHtml(NormalizeContent(converterContext.Content), GetPipeline(converterContext.PdfDocument)); + return NormalizeHtmlContent(htmlContent, converterContext.PdfDocument); + } + + protected virtual MarkdownPipeline GetPipeline(PdfDocument pdfDocument) + { + return new MarkdownPipelineBuilder() + .UseAdvancedExtensions() + .Use(new AnchorLinkResolverExtension(pdfDocument)) + .Build(); + } + + protected virtual string NormalizeContent(string content) + { + return Regex.Replace(content, @"`{3,4}json\s*//\[doc-nav\][\s\S]*?`{3,4}", string.Empty, RegexOptions.IgnoreCase); + } + + protected virtual string NormalizeHtmlContent(string htmlContent, PdfDocument pdfDocument) + { + htmlContent = WrapHtmlWithPageDiv(htmlContent, pdfDocument); + return ReplaceRelativeImageUrls(htmlContent, pdfDocument); + } + + private string WrapHtmlWithPageDiv(string htmlContent, PdfDocument pdfDocument) + { + return $"
{htmlContent}
"; + } + + private string ReplaceRelativeImageUrls(string htmlContent, PdfDocument pdfDocument) + { + return Regex.Replace(htmlContent, @"(]*)src=""([^""]*)""([^>]*>)", delegate (Match match) + { + if (UrlHelper.IsExternalLink(match.Groups[2].Value)) + { + return match.Value; + } + + var rootUrl = UrlHelper.IsExternalLink(pdfDocument.Document.RawRootUrl) + ? pdfDocument.Document.RawRootUrl.EnsureEndsWith('/') + : Options.Value.BaseUrl.EnsureEndsWith('/') + pdfDocument.Document.RawRootUrl.TrimStart('/').EnsureEndsWith('/'); + var newImageSource = rootUrl + + (pdfDocument.Document.LocalDirectory.IsNullOrEmpty() ? "" : pdfDocument.Document.LocalDirectory.TrimStart('/').EnsureEndsWith('/')) + + match.Groups[2].Value.TrimStart('/'); + + return match.Groups[1] + " src=\"" + HttpUtility.HtmlEncode(newImageSource) + "\" " + match.Groups[3]; + + }, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/PdfDocumentNode.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocument.cs similarity index 71% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/PdfDocumentNode.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocument.cs index 1abfc689cc..a0aca0c710 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/PdfDocumentNode.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocument.cs @@ -1,15 +1,16 @@ using System.Collections.Generic; using System.Linq; +using Volo.Docs.Documents; using Volo.Docs.Documents.Rendering; -namespace Volo.Docs.Documents.Pdf; +namespace Volo.Docs.Projects.Pdf; -public class PdfDocumentNode +public class PdfDocument { public Document Document { get; set; } public string Title { get; set; } public string Id { get; set; } - public List Children { get; set; } = []; + public List Children { get; set; } = []; public DocumentRenderParameters RenderParameters { get; set; } public bool HasChildren => Children.Any(); public bool IgnoreOnOutline { get; set; } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs new file mode 100644 index 0000000000..c08a4adf62 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs @@ -0,0 +1,13 @@ +namespace Volo.Docs.Projects.Pdf; + +public class PdfDocumentToHtmlConverterContext +{ + public string Content { get; set; } + public PdfDocument PdfDocument { get; set; } + + public PdfDocumentToHtmlConverterContext(string content, PdfDocument pdfDocument) + { + Content = content; + PdfDocument = pdfDocument; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs similarity index 52% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs index caa3dd38ff..8999c8ae98 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs @@ -3,119 +3,132 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Web; -using Markdig; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp; using Volo.Abp.Content; using Volo.Abp.DependencyInjection; -using Volo.Docs.Documents.Pdf.Markdig; +using Volo.Docs.Documents; using Volo.Docs.Documents.Rendering; -using Volo.Docs.Projects; -using Volo.Docs.Utils; +using Volo.Docs.HtmlConverting; using Volo.Extensions; -namespace Volo.Docs.Documents.Pdf; +namespace Volo.Docs.Projects.Pdf; -public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency +public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency { protected IDocumentSourceFactory DocumentStoreFactory { get; } + protected IDocumentToHtmlConverterFactory DocumentToHtmlConverterFactory { get; } protected IDocumentRepository DocumentRepository { get; } protected IDocumentSectionRenderer DocumentSectionRenderer { get; } - protected IOptions Options { get; } - protected IDocumentPdfFileStore DocumentPdfFileStore { get; } - protected IPdfRenderer PdfRenderer { get; } - protected ILogger Logger { get; set; } + protected IOptions Options { get; } + protected IProjectPdfFileStore ProjectPdfFileStore { get; } + protected IHtmlToPdfRenderer HtmlToPdfRenderer { get; } + protected ILogger Logger { get; set; } protected IDocumentSource DocumentSource { get; set; } protected DocumentParams DocumentParams { get; set; } - protected List AllPdfDocumentNodes { get; } = []; + protected Project Project { get; set; } + protected List AllPdfDocuments { get; } = []; - public DocumentPdfGenerator( + public ProjectPdfGenerator( IDocumentSourceFactory documentStoreFactory, IDocumentRepository documentRepository, - IOptions options, + IOptions options, IDocumentSectionRenderer documentSectionRenderer, - IDocumentPdfFileStore documentPdfFileStore, - IPdfRenderer pdfRenderer) + IProjectPdfFileStore projectPdfFileStore, + IHtmlToPdfRenderer htmlToPdfRenderer, + IDocumentToHtmlConverterFactory documentToHtmlConverterFactory) { DocumentStoreFactory = documentStoreFactory; DocumentRepository = documentRepository; Options = options; DocumentSectionRenderer = documentSectionRenderer; - DocumentPdfFileStore = documentPdfFileStore; - PdfRenderer = pdfRenderer; - Logger = NullLogger.Instance; + ProjectPdfFileStore = projectPdfFileStore; + HtmlToPdfRenderer = htmlToPdfRenderer; + DocumentToHtmlConverterFactory = documentToHtmlConverterFactory; + Logger = NullLogger.Instance; } public virtual async Task GenerateAsync(Project project, string version, string languageCode) { var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); - var fileStream = await DocumentPdfFileStore.GetOrNullAsync(project, version, languageCode); + var fileStream = await ProjectPdfFileStore.GetOrNullAsync(project, version, languageCode); if (fileStream != null) { return new RemoteStreamContent(fileStream, fileName, "application/pdf"); } + Project = project; DocumentSource = DocumentStoreFactory.Create(project.DocumentStoreType); DocumentParams = await GetDocumentParamsAsync(project, version, languageCode); + var navigation = await GetNavigationAsync(project, version, languageCode); - - await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode); - var htmlContent = await ConvertDocumentsToHtmlAsync(AllPdfDocumentNodes); + await SetAllPdfDocumentsAsync(navigation.Items, project, version, languageCode); + + var html = await BuildHtmlAsync(); + var pdfStream = await HtmlToPdfRenderer.RenderAsync(html, AllPdfDocuments); - var pdfStream = await PdfRenderer.GeneratePdfAsync(htmlContent, AllPdfDocumentNodes); - await DocumentPdfFileStore.SetAsync(project, version, languageCode, pdfStream); + await ProjectPdfFileStore.SetAsync(project, version, languageCode, pdfStream); return new RemoteStreamContent(pdfStream, fileName, "application/pdf"); } - protected virtual async Task ConvertDocumentsToHtmlAsync(List pdfDocumentNodes) + protected virtual async Task BuildHtmlAsync() + { + var htmlContent = await ConvertDocumentsToHtmlAsync(AllPdfDocuments); + + var htmlBuilder = new StringBuilder(); + htmlBuilder.Append(Options.Value.HtmlLayout); + htmlBuilder.Replace(DocsProjectPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyle); + htmlBuilder.Replace(DocsProjectPdfGeneratorOptions.ContentPlaceholder, htmlContent); + + return htmlBuilder.ToString(); + } + + protected virtual async Task ConvertDocumentsToHtmlAsync(List pdfDocuments) { var contentBuilder = new StringBuilder(); - foreach (var pdfDocumentNode in pdfDocumentNodes) + foreach (var pdfDocument in pdfDocuments) { - if (pdfDocumentNode.Document != null) + if (pdfDocument.Document != null) { - var renderedDocument = await RenderDocumentAsync(pdfDocumentNode); - renderedDocument = NormalizeHtmlContent(pdfDocumentNode, Markdown.ToHtml(renderedDocument, GetMarkdownPipeline(pdfDocumentNode))); - contentBuilder.AppendLine(renderedDocument); + var renderedDocument = await RenderDocumentAsync(pdfDocument); + var documentToHtmlConverter = GetDocumentToHtmlConverter(Project, pdfDocument); + var htmlContent = documentToHtmlConverter.Convert(new PdfDocumentToHtmlConverterContext(renderedDocument, pdfDocument)); + contentBuilder.AppendLine(htmlContent); } - if (pdfDocumentNode.HasChildren) + if (pdfDocument.HasChildren) { - contentBuilder.AppendLine(await ConvertDocumentsToHtmlAsync(pdfDocumentNode.Children)); + contentBuilder.AppendLine(await ConvertDocumentsToHtmlAsync(pdfDocument.Children)); } } return contentBuilder.ToString(); } + + protected virtual IDocumentToHtmlConverter GetDocumentToHtmlConverter(Project project, PdfDocument pdfDocument) + { + return DocumentToHtmlConverterFactory.Create(DocsDomainConsts.PdfDocumentToHtmlConverterPrefix +(pdfDocument.Document.Format ?? project.Format)); + } - protected virtual async Task RenderDocumentAsync(PdfDocumentNode pdfDocumentNode) + protected virtual async Task RenderDocumentAsync(PdfDocument pdfDocument) { - var content = NormalizeMarkdownContent(pdfDocumentNode.Document.Content); - var renderedDocument = await DocumentSectionRenderer.RenderAsync(content, pdfDocumentNode.RenderParameters); - if (pdfDocumentNode.RenderParameters != null) - { - renderedDocument = SetDocumentTitle(renderedDocument, pdfDocumentNode.Title); - } - - return renderedDocument; + return await DocumentSectionRenderer.RenderAsync(pdfDocument.Document.Content, pdfDocument.RenderParameters); } - protected virtual async Task SetAllPdfDocumentNodesAsync( + protected virtual async Task SetAllPdfDocumentsAsync( List navigations, Project project, string version, string languageCode, - PdfDocumentNode parentPdfDocumentNode = null) + PdfDocument parentPdfDocument = null) { - var groupedCombinationsDocuments = new Dictionary>(); + var groupedCombinationsDocuments = new Dictionary>(); foreach (var navigation in navigations) { if (navigation.IgnoreOnDownload) @@ -124,7 +137,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency } try { - var pdfDocumentNode = new PdfDocumentNode + var pdfDocument = new PdfDocument { Title = navigation.Text, IgnoreOnOutline = navigation.Path == Options.Value.IndexPagePath @@ -132,20 +145,19 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency if (!navigation.Path.IsNullOrWhiteSpace() && !navigation.HasChildItems) { - var path = NormalizeNavigationPath(navigation.Path); - var document = await GetDocumentAsync(project, path, version, languageCode); + var document = await GetDocumentAsync(project, navigation.Path, version, languageCode); var parameters = await DocumentSectionRenderer.GetAvailableParametersAsync(document.Content); var parameterCombinations = GenerateAllParameterCombinations(parameters.Keys.ToList(), parameters); var firstParameterCombination = parameterCombinations.FirstOrDefault(); - pdfDocumentNode.Document = document; - pdfDocumentNode.Title = GetDocumentTitle(navigation.Text, document.Content, firstParameterCombination); - pdfDocumentNode.Id = GetDocumentId(path, firstParameterCombination, true); - pdfDocumentNode.RenderParameters = firstParameterCombination; + pdfDocument.Document = document; + pdfDocument.RenderParameters = firstParameterCombination; + pdfDocument.Id = GetDocumentId(document.Name, document.Format ?? project.Format, firstParameterCombination, true); + pdfDocument.Title = GetDocumentTitle(navigation.Text, firstParameterCombination, DocumentParams); if(parameters.Count <= 1) { - AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments); + AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); } else { @@ -158,34 +170,34 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency groupedCombinationsDocuments[key] = []; } - groupedCombinationsDocuments[key].Add(new PdfDocumentNode + groupedCombinationsDocuments[key].Add(new PdfDocument { Document = document, - Title = GetDocumentTitle(navigation.Text, document.Content, parameterCombination), - Id = GetDocumentId(path, parameterCombination, false), + Id = GetDocumentId(document.Name, document.Format ?? project.Format, parameterCombination, false), + Title = GetDocumentTitle(navigation.Text, parameterCombination, DocumentParams), RenderParameters = parameterCombination }); } } } - if (parentPdfDocumentNode == null) + if (parentPdfDocument == null) { - AllPdfDocumentNodes.Add(pdfDocumentNode); + AllPdfDocuments.Add(pdfDocument); } else { - parentPdfDocumentNode.Children.Add(pdfDocumentNode); + parentPdfDocument.Children.Add(pdfDocument); } if (navigation.HasChildItems) { - await SetAllPdfDocumentNodesAsync(navigation.Items, project, version, languageCode, pdfDocumentNode); + await SetAllPdfDocumentsAsync(navigation.Items, project, version, languageCode, pdfDocument); } if (navigation == navigations.Last()) { - AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments); + AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); } } catch (Exception e) @@ -195,26 +207,21 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency } } - private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, Dictionary> groupedCombinationsDocuments) + private void AddParameterCombinationsDocuments(PdfDocument parentPdfDocument, Dictionary> groupedCombinationsDocuments) { foreach (var combinations in groupedCombinationsDocuments) { - if (parentPdfDocumentNode == null) + if (parentPdfDocument == null) { - AllPdfDocumentNodes.AddRange(combinations.Value); + AllPdfDocuments.AddRange(combinations.Value); } else { - parentPdfDocumentNode.Children.AddRange(combinations.Value); + parentPdfDocument.Children.AddRange(combinations.Value); } } } - private string NormalizeNavigationPath(string path) - { - return !path.EndsWith(".md") ? Path.Combine(path, "index.md") : path; - } - private async Task GetNavigationAsync( Project project, string version, @@ -273,19 +280,38 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency string languageCode) { version = string.IsNullOrWhiteSpace(version) ? project.LatestVersionBranchName : version; - var document = await DocumentRepository.FindAsync(project.Id, documentName, version, languageCode); + + Document document = null; - if (document != null) + Exception firstException = null; + foreach (var name in GetPossibleNames(documentName, project.Format)) { - return document; + try + { + document = await DocumentRepository.FindAsync(project.Id, documentName, version, languageCode); + if (document != null) + { + break; + } + + document = await DocumentSource.GetDocumentAsync(project, name, languageCode, version); + break; + } + catch (Exception ex) + { + firstException ??= ex; + } } - document = await DocumentSource.GetDocumentAsync(project, documentName, languageCode, version); + if(document == null) + { + throw firstException!; + } return document; } - protected virtual List GenerateAllParameterCombinations(List parameterKeys, Dictionary> parameters) + private List GenerateAllParameterCombinations(List parameterKeys, Dictionary> parameters) { var parameterCombinations = new List(); @@ -314,86 +340,86 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency } } - private string SetDocumentTitle(string content, string title) + private static string GetDocumentId(string documentName, string format, DocumentRenderParameters parameters, bool isFirstCombinationDocument) { - var titleLine = content.Split(Environment.NewLine).FirstOrDefault(x => x.TrimStart().StartsWith("#")); - if (titleLine == null) - { - return content; - } - - var newTitle = $"# {title}"; - return content.Replace(titleLine, newTitle); + var id = documentName.Replace("." + format, string.Empty).Replace("/","-").Replace(" ", "-").ToLower(); + if (parameters != null && !isFirstCombinationDocument) + { + id = $"{id}{parameters.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-")}"; + } + + return id; } - private string GetDocumentTitle(string title, string content, DocumentRenderParameters parameters) + private static string GetDocumentTitle(string title, DocumentRenderParameters parameters, DocumentParams documentParams) { if (parameters == null || parameters.Count <= 0) { return title; } - var titleLine = content.Split(Environment.NewLine).FirstOrDefault(x => x.TrimStart().StartsWith("#")); - if (titleLine == null) + var paramValues = parameters.Select(x => { - return title; - } + var documentParam = documentParams.Parameters.FirstOrDefault(p => p.Name == x.Key); + return $"{documentParam?.DisplayName ?? x.Key} : {documentParam?.Values[x.Value] ?? x.Value}"; + }); - var paramValues = parameters.Select(x => $"{DocumentParams.Parameters.FirstOrDefault(p => p.Name == x.Key)?.DisplayName ?? x.Key}: {x.Value}").ToList(); - return titleLine.TrimStart('#').Trim() + $" ({string.Join(", ", paramValues)})"; - } - - private string GetDocumentId(string path, DocumentRenderParameters parameters, bool isFirstCombinationDocument) - { - var id = path.Replace(".md",string.Empty).Replace("/","-").Replace(" ", "-").ToLower(); - if (parameters != null && !isFirstCombinationDocument) - { - id = $"{id}{parameters.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-")}"; - } - - return id; + return title.Trim() + $" ({string.Join(", ", paramValues)})"; } - private string NormalizeHtmlContent(PdfDocumentNode pdfDocumentNode, string htmlContent) + private static List GetPossibleNames(string originalDocumentName, string format) { - htmlContent = $"
{htmlContent}
"; - htmlContent = ReplaceRelativeImageUrls(pdfDocumentNode, htmlContent); + var extension = Path.GetExtension(originalDocumentName); + if (extension.IsNullOrWhiteSpace()) + { + extension = "." + format; + } + + if (!extension.Equals("." + format, StringComparison.OrdinalIgnoreCase)) + { + return [originalDocumentName]; + } - return htmlContent; - } + var lowerCaseIndex = "index." + format; + var titleCaseIndex = "Index." + format; + var indexLength = lowerCaseIndex.Length; - private string ReplaceRelativeImageUrls(PdfDocumentNode pdfDocumentNode, string htmlContent) - { - return Regex.Replace(htmlContent, @"(]*)src=""([^""]*)""([^>]*>)", delegate (Match match) + var possibleNames = new List {originalDocumentName}; + if (originalDocumentName.EndsWith("/" + lowerCaseIndex, StringComparison.OrdinalIgnoreCase) || originalDocumentName.Equals(lowerCaseIndex, StringComparison.OrdinalIgnoreCase)) { - if (UrlHelper.IsExternalLink(match.Groups[2].Value)) + var indexPart = originalDocumentName.Right(indexLength); + + var documentNameWithoutIndex = originalDocumentName.Left(originalDocumentName.Length - lowerCaseIndex.Length); + + if(indexPart != lowerCaseIndex) { - return match.Value; + possibleNames.Add(documentNameWithoutIndex + lowerCaseIndex); } - var rootUrl = UrlHelper.IsExternalLink(pdfDocumentNode.Document.RawRootUrl) - ? pdfDocumentNode.Document.RawRootUrl.EnsureEndsWith('/') - : Options.Value.BaseUrl.EnsureEndsWith('/') + pdfDocumentNode.Document.RawRootUrl.TrimStart('/').EnsureEndsWith('/'); - var newImageSource = rootUrl + - (pdfDocumentNode.Document.LocalDirectory.IsNullOrEmpty() ? "" : pdfDocumentNode.Document.LocalDirectory.TrimStart('/').EnsureEndsWith('/')) + - match.Groups[2].Value.TrimStart('/'); - - return match.Groups[1] + " src=\"" + HttpUtility.HtmlEncode(newImageSource) + "\" " + match.Groups[3]; + if(indexPart != titleCaseIndex) + { + possibleNames.Add(documentNameWithoutIndex + titleCaseIndex); + } + } + else + { + var documentNameWithoutExtension = RemoveFileExtensionFromPath(originalDocumentName, format).EnsureEndsWith('/'); + possibleNames.Add(documentNameWithoutExtension + lowerCaseIndex); + possibleNames.Add(documentNameWithoutExtension + titleCaseIndex); + } - }, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline); + return possibleNames; } - - private string NormalizeMarkdownContent(string content) + + private static string RemoveFileExtensionFromPath(string path, string format) { - var pattern = @"`{3,4}json\s*//\[doc-nav\][\s\S]*?`{3,4}"; - return Regex.Replace(content, pattern, string.Empty, RegexOptions.IgnoreCase); - } + if (path == null) + { + return null; + } - private MarkdownPipeline GetMarkdownPipeline(PdfDocumentNode pdfDocumentNode) - { - return new MarkdownPipelineBuilder() - .UseAdvancedExtensions() - .Use(new AnchorLinkResolverExtension(pdfDocumentNode)) - .Build(); + return path.EndsWith("." + format) + ? path.Left(path.Length - format.Length - 1) + : path; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs index 48eb93d19e..69fa3a7056 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using JetBrains.Annotations; using Volo.Abp; using Volo.Abp.Domain.Entities; @@ -47,9 +48,12 @@ namespace Volo.Docs.Projects public virtual string MainWebsiteUrl { get; set; } public virtual string LatestVersionBranchName { get; set; } + + public virtual List PdfFiles { get; set; } protected Project() { + PdfFiles = new List(); } public Project( @@ -103,5 +107,24 @@ namespace Volo.Docs.Projects { ShortName = ShortName.ToLower(); } + + public virtual ProjectPdfFile FindPdfFile(string fileName) + { + return PdfFiles.Find(x => x.FileName == fileName); + } + + public virtual void AddPdfFile(Guid projectId, string fileName, string version, string languageCode) + { + PdfFiles.Add(new ProjectPdfFile(projectId, fileName, version, languageCode)); + } + + public virtual void RemovePdfFile(string fileName) + { + var pdfFile = FindPdfFile(fileName); + if (pdfFile != null) + { + PdfFiles.Remove(pdfFile); + } + } } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/ProjectPdfFile.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/ProjectPdfFile.cs new file mode 100644 index 0000000000..135ca3b01e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/ProjectPdfFile.cs @@ -0,0 +1,38 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Domain.Entities; + +namespace Volo.Docs.Projects; + +public class ProjectPdfFile : Entity, IHasCreationTime, IHasModificationTime +{ + public virtual Guid ProjectId { get; set; } + public virtual string FileName { get; set; } + public virtual string Version { get; set; } + public virtual string LanguageCode { get; set; } + public virtual DateTime CreationTime { get; set; } + public virtual DateTime? LastModificationTime { get; set; } + + protected ProjectPdfFile() + { + + } + + public ProjectPdfFile(Guid projectId, string fileName, string version, string languageCode) + { + ProjectId = projectId; + FileName = fileName; + Version = version; + LanguageCode = languageCode; + } + + public override object[] GetKeys() + { + return [ProjectId, FileName]; + } + + public virtual bool Equals(Guid projectId, string fileName) + { + return ProjectId == projectId && FileName == fileName; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs index 9ce0c59dc3..56b2204bc5 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs @@ -16,6 +16,8 @@ namespace Volo.Docs.EntityFrameworkCore public DbSet Documents { get; set; } public DbSet DocumentContributors { get; set; } + + public DbSet ProjectPdfFiles { get; set; } public DocsDbContext(DbContextOptions options) : base(options) diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs index 745b822f17..86f230164f 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs @@ -31,6 +31,10 @@ namespace Volo.Docs.EntityFrameworkCore b.Property(x => x.NavigationDocumentName).IsRequired().HasMaxLength(ProjectConsts.MaxNavigationDocumentNameLength); b.Property(x => x.ParametersDocumentName).IsRequired().HasMaxLength(ProjectConsts.MaxParametersDocumentNameLength); b.Property(x => x.LatestVersionBranchName).HasMaxLength(ProjectConsts.MaxLatestVersionBranchNameLength); + + b.HasMany(x => x.PdfFiles).WithOne() + .HasForeignKey(x => new { x.ProjectId }) + .IsRequired(); b.ApplyObjectExtensionMappings(); }); @@ -69,6 +73,17 @@ namespace Volo.Docs.EntityFrameworkCore b.ApplyObjectExtensionMappings(); }); + + builder.Entity(b => + { + b.ToTable(AbpDocsDbProperties.DbTablePrefix + "ProjectPdfFiles", AbpDocsDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.HasKey(x => new { x.ProjectId, x.FileName }); + + b.ApplyObjectExtensionMappings(); + }); builder.TryConfigureObjectExtensions(); } diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs index 0bd2e4fff8..89aff2cf3c 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Volo.Docs.Documents; +using Volo.Docs.Projects; namespace Volo.Docs.EntityFrameworkCore { @@ -10,5 +11,10 @@ namespace Volo.Docs.EntityFrameworkCore { return !include ? queryable : queryable.Include(x => x.Contributors); } + + public static IQueryable IncludeDetails(this IQueryable queryable, bool include = true) + { + return !include ? queryable : queryable.Include(x => x.PdfFiles); + } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs index e85f9b4aa5..69ab6f7b1d 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs @@ -16,5 +16,7 @@ namespace Volo.Docs.EntityFrameworkCore DbSet Documents { get; } DbSet DocumentContributors { get; } + + DbSet ProjectPdfFiles { get; set; } } } diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs index cbdf4cec06..e7db47335c 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs @@ -19,9 +19,14 @@ namespace Volo.Docs.Projects { } - public virtual async Task> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync( + string sorting, + int maxResultCount, + int skipCount, + bool includeDetails = false, + CancellationToken cancellationToken = default) { - var projects = await (await GetDbSetAsync()).OrderBy(sorting.IsNullOrEmpty() ? "Id desc" : sorting) + var projects = await (await GetDbSetAsync()).IncludeDetails(includeDetails).OrderBy(sorting.IsNullOrEmpty() ? "Id desc" : sorting) .PageBy(skipCount, maxResultCount) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -64,5 +69,10 @@ namespace Volo.Docs.Projects { return shortName.ToLower(); } + + public async override Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs index af54bd6bc5..95b2ed0244 100644 --- a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs @@ -20,7 +20,12 @@ namespace Volo.Docs.Projects { } - public virtual async Task> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync( + string sorting, + int maxResultCount, + int skipCount, + bool includeDetails = false, + CancellationToken cancellationToken = default) { var projects = await (await GetQueryableAsync(cancellationToken)).OrderBy(sorting.IsNullOrEmpty() ? "Id desc" : sorting).PageBy(skipCount, maxResultCount) .ToListAsync(GetCancellationToken(cancellationToken)); diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterContext.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterContext.cs new file mode 100644 index 0000000000..53a5c4d631 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterContext.cs @@ -0,0 +1,26 @@ +using Volo.Docs.Common.Projects; +using Volo.Docs.Documents; + +namespace Volo.Docs.HtmlConverting; + +public class DocumentToHtmlConverterContext +{ + public ProjectDto Project { get; set; } + public DocumentWithDetailsDto Document { get; set; } + public string Version { get; set; } + public string LanguageCode { get; set; } + public string ProjectShortName { get; set; } + + public DocumentToHtmlConverterContext(ProjectDto project, + DocumentWithDetailsDto document, + string version, + string languageCode, + string projectShortName = null) + { + Project = project; + Document = document; + Version = version; + LanguageCode = languageCode; + ProjectShortName = projectShortName; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterOptions.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterOptions.cs deleted file mode 100644 index f332f6f58a..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterOptions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Volo.Docs.HtmlConverting -{ - public class DocumentToHtmlConverterOptions - { - public Dictionary Converters { get; set; } - - public DocumentToHtmlConverterOptions() - { - Converters = new Dictionary(); - } - } -} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs deleted file mode 100644 index dc891f7ca4..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Volo.Docs.Common.Projects; -using Volo.Docs.Documents; - -namespace Volo.Docs.HtmlConverting -{ - public interface IDocumentToHtmlConverter - { - string Convert(ProjectDto project, DocumentWithDetailsDto document, string version, string languageCode, string projectShortName = null); - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverterFactory.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverterFactory.cs deleted file mode 100644 index 9cdca43a8f..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverterFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Volo.Docs.HtmlConverting -{ - public interface IDocumentToHtmlConverterFactory - { - IDocumentToHtmlConverter Create(string format); - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs index 72d280f300..54df0c4440 100644 --- a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs @@ -10,7 +10,7 @@ using Volo.Docs.Utils; namespace Volo.Docs.Markdown { - public class MarkdownDocumentToHtmlConverter : IDocumentToHtmlConverter, ITransientDependency + public class MarkdownDocumentToHtmlConverter : IDocumentToHtmlConverter, ITransientDependency { public const string Type = "md"; @@ -30,20 +30,19 @@ namespace Volo.Docs.Markdown private const string MarkdownLinkRegExp = @"\[(.*?)\]\(((.*?)(\?(.*?))*?)\)"; private const string AnchorLinkRegExp = @"]+href=\""(.*?)\""[^>]*>(.*)?
"; - public virtual string Convert(ProjectDto project, DocumentWithDetailsDto document, string version, - string languageCode, string projectShortName = null) + public virtual string Convert(DocumentToHtmlConverterContext context) { - if (document.Content.IsNullOrEmpty()) + if (context.Document.Content.IsNullOrEmpty()) { - return document.Content; + return context.Document.Content; } var content = NormalizeLinks( - document.Content, - _uiOptions.SingleProjectMode.Enable ? projectShortName : projectShortName ?? project.ShortName, - version, - document.LocalDirectory, - !_uiOptions.MultiLanguageMode ? languageCode : languageCode ?? document.LanguageCode + context.Document.Content, + _uiOptions.SingleProjectMode.Enable ? context.ProjectShortName : context.ProjectShortName ?? context.Project.ShortName, + context.Version, + context.Document.LocalDirectory, + !_uiOptions.MultiLanguageMode ? context.LanguageCode : context.LanguageCode ?? context.Document.LanguageCode ); var html = _markdownConverter.ConvertToHtml(content); diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index b0c2a0b2c0..471747fac1 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -7,14 +7,11 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; @@ -155,7 +152,7 @@ namespace Volo.Docs.Pages.Documents.Project ShowProjectsCombobox = _uiOptions.ShowProjectsCombobox && !_uiOptions.SingleProjectMode.Enable; ShowProjectsComboboxLabel = ShowProjectsCombobox && _uiOptions.ShowProjectsComboboxLabel; FullSearchEnabled = await _documentAppService.FullSearchEnabledAsync(); - HasDownloadPdfPermission = await _permissionChecker.IsGrantedAsync(DocsCommonPermissions.Documents.PdfGeneration); + HasDownloadPdfPermission = await _permissionChecker.IsGrantedAsync(DocsCommonPermissions.Projects.PdfGeneration); try { await SetProjectAsync(); @@ -586,8 +583,8 @@ namespace Volo.Docs.Pages.Documents.Project DocumentNavigationsDto = new DocumentNavigationsDto(); } - var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format); - var content = converter.Convert(Project, Document, GetSpecificVersionOrLatest(), LanguageCode, ProjectName); + var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format); + var content = converter.Convert(new DocumentToHtmlConverterContext(Project, Document, GetSpecificVersionOrLatest(), LanguageCode, ProjectName)); content = HtmlNormalizer.ReplaceImageSources( content, @@ -782,8 +779,6 @@ namespace Volo.Docs.Pages.Documents.Project } var availableParameters = await _webDocumentSectionRenderer.GetAvailableParametersAsync(Document.Content); - var parameterCombinations = new List>(); - GenerateCombinations(0, availableParameters.Keys.ToList(),availableParameters,new Dictionary(), parameterCombinations); DocumentPreferences = new DocumentParametersDto { @@ -829,27 +824,6 @@ namespace Volo.Docs.Pages.Documents.Project AlternativeOptionLinkQueries = CollectAlternativeOptionLinksRecursively(); } - - void GenerateCombinations( - int keyIndex, - List parameterKeys , - Dictionary> parameters, - Dictionary currentCombination, - List> parameterCombinations ) - { - if (keyIndex == parameterKeys.Count) - { - parameterCombinations.Add(new Dictionary(currentCombination)); - return; - } - - var currentKey = parameterKeys[keyIndex]; - foreach (var value in parameters[currentKey]) - { - currentCombination[currentKey] = value; - GenerateCombinations(keyIndex + 1,parameterKeys, parameters, currentCombination,parameterCombinations); - } - } private List CollectAlternativeOptionLinksRecursively(int index = 0) { From 2187c75352b06408dd2980b30aa0d4ff85f12ecd Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 28 Apr 2025 15:45:52 +0800 Subject: [PATCH 12/19] update ManagePdfFiles.cshtml --- .../Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml | 2 +- .../src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml index de1034112e..e4d9ecda72 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml @@ -36,6 +36,6 @@ - + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js index a367cda36e..12ad8f2d95 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js @@ -125,7 +125,7 @@ $(function () { { text: l('ManagePdfFiles'), visible: abp.auth.isGranted( - 'Docs.Admin.Documents' + 'Docs.Admin.Projects.ManagePdfFiles' ), action: function (data) { _managePdfFilesModal.open({ From a6554e8bbf4bbcdddc7a945d4325f88501929e3c Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 28 Apr 2025 15:48:30 +0800 Subject: [PATCH 13/19] Update managePdfFiles.js --- .../Pages/Docs/Admin/Projects/managePdfFiles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js index 72a7aaa1ee..8481867f46 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js @@ -34,7 +34,7 @@ $(function () { { text: l('Delete'), confirmMessage: function (data) { - return l('PdfFileDeletionWarningMessage', { fileName: data.record.fileName }); + return l('PdfFileDeletionWarningMessage', data.record.fileName); }, action: function (data) { projectAdminAppService.deletePdfFile({ From df7792fbe5cf6e2c016778b495ea8b5ca310b011 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Fri, 2 May 2025 13:26:39 +0800 Subject: [PATCH 14/19] Delete PDF file from blob container --- .../Volo/Docs/Admin/Projects/ProjectAdminAppService.cs | 10 ++++------ .../Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs | 10 ++++++++++ .../Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs | 2 ++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs index 0c06fb23a8..abbb26abe5 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs @@ -23,14 +23,14 @@ namespace Volo.Docs.Admin.Projects private readonly IDocumentRepository _documentRepository; private readonly IDocumentFullSearch _elasticSearchService; private readonly IGuidGenerator _guidGenerator; - private readonly IOptions _pdfGeneratorOptions; + private readonly IProjectPdfFileStore _projectPdfFileStore; public ProjectAdminAppService( IProjectRepository projectRepository, IDocumentRepository documentRepository, IDocumentFullSearch elasticSearchService, IGuidGenerator guidGenerator, - IOptions pdfGeneratorOptions) + IProjectPdfFileStore projectPdfFileStore) { ObjectMapperContext = typeof(DocsAdminApplicationModule); LocalizationResource = typeof(DocsResource); @@ -39,7 +39,7 @@ namespace Volo.Docs.Admin.Projects _documentRepository = documentRepository; _elasticSearchService = elasticSearchService; _guidGenerator = guidGenerator; - _pdfGeneratorOptions = pdfGeneratorOptions; + _projectPdfFileStore = projectPdfFileStore; } public virtual async Task> GetListAsync(PagedAndSortedResultRequestDto input) @@ -199,9 +199,7 @@ namespace Volo.Docs.Admin.Projects public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) { var project = await _projectRepository.GetAsync(input.ProjectId, includeDetails: true); - project.RemovePdfFile(_pdfGeneratorOptions.Value.CalculatePdfFileName(project, input.Version, input.LanguageCode)); - - await _projectRepository.UpdateAsync(project); + await _projectPdfFileStore.DeleteAsync(project, input.Version, input.LanguageCode); } } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs index 8f3cca16aa..315d89c49c 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs @@ -61,4 +61,14 @@ public class BlobProjectPdfFileStore : IProjectPdfFileStore, ITransientDependenc return await BlobContainer.GetOrNullAsync(Options.Value.CalculatePdfFileName(project, version, languageCode)); } + + public virtual async Task DeleteAsync(Project project, string version, string languageCode) + { + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + + await BlobContainer.DeleteAsync(fileName); + project.RemovePdfFile(fileName); + await ProjectRepository.UpdateAsync(project); + + } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs index 2dfc203400..4f11d9cad2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs @@ -8,4 +8,6 @@ public interface IProjectPdfFileStore Task SetAsync(Project project, string version, string languageCode, Stream stream); Task GetOrNullAsync(Project project, string version, string languageCode); + + Task DeleteAsync(Project project, string version, string languageCode); } \ No newline at end of file From 75e7d5a656f5b287be3ad32b47850b43bb9ef920 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Sat, 3 May 2025 15:16:48 +0800 Subject: [PATCH 15/19] update vs.css --- .../docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css | 2 +- .../src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css index 32017cd466..36ca24e100 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css @@ -219,7 +219,7 @@ body.scrolledMore .alert-criteria p.alert-p { } .docs-page .docs-sidebar .docs-tree-list > ul { display: block; - height: calc(100vh - 310px); + height: calc(100vh - 350px); overflow-y: auto; margin-right: -4px !important; margin-top: 20px !important; diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss index 6c2c4c7627..deba3d39c3 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss @@ -268,7 +268,7 @@ body { > ul { display: block; - height: calc(100vh - 310px); + height: calc(100vh - 350px); overflow-y: auto; margin-right: -4px !important; margin-top: 20px !important; From 20275794d472493dd098939fa2bcaa5b1dd6b03c Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Sat, 3 May 2025 15:48:58 +0800 Subject: [PATCH 16/19] Set PDF file title --- modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs | 1 + .../Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs | 6 ++++++ .../Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs | 2 +- .../Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs | 3 ++- .../Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs | 3 ++- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index f48879b43a..03875dd6dd 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -179,6 +179,7 @@ namespace VoloDocs.Web { options.BaseUrl = configuration["App:selfUrl"]; options.IndexPagePath = "Index.md"; + options.CalculatePdfFileTitle = project => project.ShortName == "abp" ? "ABP Documentation" : null; }); Configure(options => diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs index 708dd7f94d..39a7716e68 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs @@ -1,4 +1,5 @@ using System; +using Scriban.Syntax; namespace Volo.Docs.Projects.Pdf; @@ -40,6 +41,11 @@ public class DocsProjectPdfGeneratorOptions /// public Func CalculatePdfFileName { get; set; } + /// + /// The function to calculate the PDF file title. + /// + public Func CalculatePdfFileTitle { get; set; } + public DocsProjectPdfGeneratorOptions() { HtmlLayout = $@" diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs index f134b0cdb2..c17908af51 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs @@ -6,5 +6,5 @@ namespace Volo.Docs.Projects.Pdf; public interface IHtmlToPdfRenderer { - Task RenderAsync(string html, List documents); + Task RenderAsync(string title, string html, List documents); } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs index 9ecc866105..e28113d762 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs @@ -20,11 +20,12 @@ public class ITextHtmlToPdfRenderer : IHtmlToPdfRenderer ,ITransientDependency Options = options; } - public virtual Task RenderAsync(string html, List documents) + public virtual Task RenderAsync(string title, string html, List documents) { var pdfStream = new MemoryStream(); var pdfWrite = new PdfWriter(pdfStream); var pdfDocument = new iText.Kernel.Pdf.PdfDocument(pdfWrite); + pdfDocument.GetDocumentInfo().SetTitle(title); var textDocument = new ITextDocument(pdfDocument); pdfWrite.SetCloseStream(false); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs index 8999c8ae98..218d790898 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs @@ -69,7 +69,8 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency await SetAllPdfDocumentsAsync(navigation.Items, project, version, languageCode); var html = await BuildHtmlAsync(); - var pdfStream = await HtmlToPdfRenderer.RenderAsync(html, AllPdfDocuments); + var title = Options.Value.CalculatePdfFileTitle?.Invoke(project) ?? project.Name; + var pdfStream = await HtmlToPdfRenderer.RenderAsync(title, html, AllPdfDocuments); await ProjectPdfFileStore.SetAsync(project, version, languageCode, pdfStream); From 8b7450072366a48f0cc5299e150053ac83b5c822 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 6 May 2025 13:23:11 +0800 Subject: [PATCH 17/19] Set content title --- .../Volo/Docs/DocsDomainModule.cs | 1 - .../AnchorLinkRenderer.cs | 0 .../AnchorLinkResolverExtension.cs | 0 .../MarkdigPdfDocumentToHtmlConverter.cs | 36 ++++++++++++++++--- .../Pdf/PdfDocumentToHtmlConverterContext.cs | 7 +++- .../Docs/Projects/Pdf/ProjectPdfGenerator.cs | 2 +- 6 files changed, 38 insertions(+), 8 deletions(-) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/{Markdown => Markdig}/AnchorLinkRenderer.cs (100%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/{Markdown => Markdig}/AnchorLinkResolverExtension.cs (100%) rename modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/{Markdown => Markdig}/MarkdigPdfDocumentToHtmlConverter.cs (66%) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs index b4f6927ce0..502b2f9065 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs @@ -21,7 +21,6 @@ using Volo.Docs.HtmlConverting; using Volo.Docs.Localization; using Volo.Docs.Projects; using Volo.Docs.Projects.Pdf.Markdig; -using Volo.Docs.Projects.Pdf.Markdown; namespace Volo.Docs { diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkRenderer.cs similarity index 100% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkRenderer.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkRenderer.cs diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkResolverExtension.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkResolverExtension.cs similarity index 100% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/AnchorLinkResolverExtension.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkResolverExtension.cs diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/MarkdigPdfDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs similarity index 66% rename from modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/MarkdigPdfDocumentToHtmlConverter.cs rename to modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs index 105db5a956..0d50244ee9 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdown/MarkdigPdfDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs @@ -1,14 +1,16 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; using System.Web; using Markdig; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; +using Volo.Docs.Documents; using Volo.Docs.HtmlConverting; -using Volo.Docs.Projects.Pdf.Markdig; using Volo.Docs.Utils; -namespace Volo.Docs.Projects.Pdf.Markdown; +namespace Volo.Docs.Projects.Pdf.Markdig; public class MarkdigPdfDocumentToHtmlConverter : IDocumentToHtmlConverter, ITransientDependency { @@ -22,7 +24,11 @@ public class MarkdigPdfDocumentToHtmlConverter : IDocumentToHtmlConverter x.TrimStart().StartsWith("#")); + if (titleLine == null) + { + return content; + } + + var paramValues = pdfDocument.RenderParameters.Select(x => + { + var documentParam = documentParams.Parameters.FirstOrDefault(p => p.Name == x.Key); + return $"{documentParam?.Values[x.Value] ?? x.Value}"; + }); + + var newTitle = $"{titleLine.Trim()} ({string.Join(", ", paramValues)})"; + return content.Replace(titleLine, newTitle); } protected virtual string NormalizeHtmlContent(string htmlContent, PdfDocument pdfDocument) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs index c08a4adf62..5a99d46634 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs @@ -1,3 +1,5 @@ +using Volo.Docs.Documents; + namespace Volo.Docs.Projects.Pdf; public class PdfDocumentToHtmlConverterContext @@ -5,9 +7,12 @@ public class PdfDocumentToHtmlConverterContext public string Content { get; set; } public PdfDocument PdfDocument { get; set; } - public PdfDocumentToHtmlConverterContext(string content, PdfDocument pdfDocument) + public DocumentParams DocumentParams { get; set; } + + public PdfDocumentToHtmlConverterContext(string content, PdfDocument pdfDocument, DocumentParams documentParams) { Content = content; PdfDocument = pdfDocument; + DocumentParams = documentParams; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs index 218d790898..9a29a7776f 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs @@ -99,7 +99,7 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency { var renderedDocument = await RenderDocumentAsync(pdfDocument); var documentToHtmlConverter = GetDocumentToHtmlConverter(Project, pdfDocument); - var htmlContent = documentToHtmlConverter.Convert(new PdfDocumentToHtmlConverterContext(renderedDocument, pdfDocument)); + var htmlContent = documentToHtmlConverter.Convert(new PdfDocumentToHtmlConverterContext(renderedDocument, pdfDocument, DocumentParams)); contentBuilder.AppendLine(htmlContent); } From e27b48c5429fe8d0b8c7d8d966e0d5585135e743 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Fri, 9 May 2025 13:50:05 +0800 Subject: [PATCH 18/19] Fix problems --- .../Pdf/DocsProjectPdfGeneratorOptions.cs | 20 +++++++++++++++---- .../Docs/Projects/Pdf/ProjectPdfGenerator.cs | 8 ++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs index 39a7716e68..8ab7bbbbea 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs @@ -62,16 +62,18 @@ public class DocsProjectPdfGeneratorOptions "; HtmlStyle = @" - body { margin: 20px; line-height: 1.6; font-family: Arial, sans-serif;} - a { text-decoration: none; } + body { margin: 15px; line-height: 1.5; font-family: Arial, sans-serif;} + a { text-decoration: none; word-break: break-all; overflow-wrap: break-word;} + li { word-break: break-all; overflow-wrap: break-word; } .page { page-break-after: always; margin-bottom: 30px; padding: 15px; } img { - max-width:100%; - height: auto; + max-width: 100%; + max-height: 850px; + object-fit: contain; display: block; } code, pre { @@ -97,6 +99,16 @@ public class DocsProjectPdfGeneratorOptions margin: 20px 0; padding: 10px 20px; background: #f8fafc; + } + table { width: 100%; border-collapse: collapse; table-layout: fixed; } + table img { width: 100% !important; height: auto; display: block; } + th { font-weight: bold; background-color: #f5f5f5; } + th, td { + border: 1px solid #333; + padding: 6px 10px; + word-break: break-all; + overflow-wrap: break-word; + width: 100%; }"; CalculatePdfFileName = (project, version, languageCode) => $"{project.ShortName}-{version}-{languageCode}.pdf"; diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs index 9a29a7776f..943b5d976b 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs @@ -184,11 +184,11 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency if (parentPdfDocument == null) { - AllPdfDocuments.Add(pdfDocument); + AllPdfDocuments.AddIfNotContains(pdfDocument); } else { - parentPdfDocument.Children.Add(pdfDocument); + parentPdfDocument.Children.AddIfNotContains(pdfDocument); } if (navigation.HasChildItems) @@ -214,11 +214,11 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency { if (parentPdfDocument == null) { - AllPdfDocuments.AddRange(combinations.Value); + AllPdfDocuments.AddIfNotContains(combinations.Value); } else { - parentPdfDocument.Children.AddRange(combinations.Value); + parentPdfDocument.Children.AddIfNotContains(combinations.Value); } } } From 6a154d9846b1411176eec790b16f7408243bdf82 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 12 May 2025 12:00:48 +0800 Subject: [PATCH 19/19] Add HandleLeafDocumentAsync method and fix problems --- docs/en/docs-nav.json | 64 ++++++--- .../app/VoloDocs.Web/VoloDocsWebModule.cs | 1 + .../Volo/Docs/Documents/NavigationNode.cs | 3 + .../Pdf/DocsProjectPdfGeneratorOptions.cs | 4 + .../Pdf/IText/ITextHtmlToPdfRenderer.cs | 3 +- .../MarkdigPdfDocumentToHtmlConverter.cs | 51 ++++--- .../Docs/Projects/Pdf/ProjectPdfGenerator.cs | 131 ++++++++++++------ 7 files changed, 174 insertions(+), 83 deletions(-) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index fc3844317d..d031e87466 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -83,47 +83,59 @@ { "text": "Overview", "path": "tutorials/book-store", - "isIndex": true + "isIndex": true, + "isInSeries": true }, { "text": "1: Creating the Server Side", - "path": "tutorials/book-store/part-01.md" + "path": "tutorials/book-store/part-01.md", + "isInSeries": true + }, { "text": "2: The Book List Page", - "path": "tutorials/book-store/part-02.md" + "path": "tutorials/book-store/part-02.md", + "isInSeries": true }, { "text": "3: Creating, Updating and Deleting Books", - "path": "tutorials/book-store/part-03.md" + "path": "tutorials/book-store/part-03.md", + "isInSeries": true }, { "text": "4: Integration Tests", - "path": "tutorials/book-store/part-04.md" + "path": "tutorials/book-store/part-04.md", + "isInSeries": true }, { "text": "5: Authorization", - "path": "tutorials/book-store/part-05.md" + "path": "tutorials/book-store/part-05.md", + "isInSeries": true }, { "text": "6: Authors: Domain Layer", - "path": "tutorials/book-store/part-06.md" + "path": "tutorials/book-store/part-06.md", + "isInSeries": true }, { "text": "7: Authors: Database Integration", - "path": "tutorials/book-store/part-07.md" + "path": "tutorials/book-store/part-07.md", + "isInSeries": true }, { "text": "8: Authors: Application Layer", - "path": "tutorials/book-store/part-08.md" + "path": "tutorials/book-store/part-08.md", + "isInSeries": true }, { "text": "9: Authors: User Interface", - "path": "tutorials/book-store/part-09.md" + "path": "tutorials/book-store/part-09.md", + "isInSeries": true }, { "text": "10: Book to Author Relation", - "path": "tutorials/book-store/part-10.md" + "path": "tutorials/book-store/part-10.md", + "isInSeries": true } ] }, @@ -135,27 +147,33 @@ { "text": "Overview", "path": "tutorials/book-store-with-abp-suite", - "isIndex": true + "isIndex": true, + "isInSeries": true }, { "text": "1: Creating the Solution", - "path": "tutorials/book-store-with-abp-suite/part-01.md" + "path": "tutorials/book-store-with-abp-suite/part-01.md", + "isInSeries": true }, { "text": "2: Creating the Books", - "path": "tutorials/book-store-with-abp-suite/part-02.md" + "path": "tutorials/book-store-with-abp-suite/part-02.md", + "isInSeries": true }, { "text": "3: Creating the Authors", - "path": "tutorials/book-store-with-abp-suite/part-03.md" + "path": "tutorials/book-store-with-abp-suite/part-03.md", + "isInSeries": true }, { "text": "4: Book to Author Relation", - "path": "tutorials/book-store-with-abp-suite/part-04.md" + "path": "tutorials/book-store-with-abp-suite/part-04.md", + "isInSeries": true }, { "text": "5: Customizing the Generated Code", - "path": "tutorials/book-store-with-abp-suite/part-05.md" + "path": "tutorials/book-store-with-abp-suite/part-05.md", + "isInSeries": true } ] }, @@ -2070,19 +2088,23 @@ "items": [ { "text": "Deploy to Azure Web App Service", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md", + "isInSeries": true }, { "text": "Creating an Azure Web App Service Environment", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md", + "isInSeries": true }, { "text": "Customizing the Configuration of Your ABP Application", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md", + "isInSeries": true }, { "text": "Deploying Application With GitHub Actions", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md", + "isInSeries": true } ] }, diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index 03875dd6dd..297a15c88d 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -180,6 +180,7 @@ namespace VoloDocs.Web options.BaseUrl = configuration["App:selfUrl"]; options.IndexPagePath = "Index.md"; options.CalculatePdfFileTitle = project => project.ShortName == "abp" ? "ABP Documentation" : null; + options.DocumentContentNormalizer = content => content.Replace("", "No").Replace("", "Yes"); }); Configure(options => 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 9b270297a7..43ebfa9a76 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 @@ -27,6 +27,9 @@ namespace Volo.Docs.Documents [JsonPropertyName("ignoreOnDownload")] public bool IgnoreOnDownload { get; set; } + + [JsonPropertyName("isInSeries")] + public bool IsInSeries { get; set; } public bool IsLeaf => !HasChildItems; diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs index 8ab7bbbbea..ef24e6ffd7 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs @@ -46,6 +46,10 @@ public class DocsProjectPdfGeneratorOptions /// public Func CalculatePdfFileTitle { get; set; } + public Func HtmlContentNormalizer { get; set; } + + public Func DocumentContentNormalizer { get; set; } + public DocsProjectPdfGeneratorOptions() { HtmlLayout = $@" diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs index e28113d762..1ee6b679e3 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs @@ -7,6 +7,7 @@ using iText.Kernel.Pdf; using iText.Kernel.Pdf.Action; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; +using Volo.Docs.Utils; using ITextDocument = iText.Layout.Document; namespace Volo.Docs.Projects.Pdf.IText; @@ -56,7 +57,7 @@ public class ITextHtmlToPdfRenderer : IHtmlToPdfRenderer ,ITransientDependency var outline = parentOutline.AddOutline(pdfDocumentNode.Title); if (!pdfDocumentNode.Id.IsNullOrWhiteSpace()) { - outline.AddAction(PdfAction.CreateGoTo(pdfDocumentNode.Id)); + outline.AddAction(UrlHelper.IsExternalLink(pdfDocumentNode.Id) ? PdfAction.CreateURI(pdfDocumentNode.Id) : PdfAction.CreateGoTo(pdfDocumentNode.Id)); } if (pdfDocumentNode.HasChildren) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs index 0d50244ee9..22c94b5930 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs @@ -36,6 +36,7 @@ public class MarkdigPdfDocumentToHtmlConverter : IDocumentToHtmlConverter x.TrimStart().StartsWith("#")); - if (titleLine == null) - { - return content; - } - - var paramValues = pdfDocument.RenderParameters.Select(x => - { - var documentParam = documentParams.Parameters.FirstOrDefault(p => p.Name == x.Key); - return $"{documentParam?.Values[x.Value] ?? x.Value}"; - }); - - var newTitle = $"{titleLine.Trim()} ({string.Join(", ", paramValues)})"; - return content.Replace(titleLine, newTitle); + return Options.Value.DocumentContentNormalizer(content); } protected virtual string NormalizeHtmlContent(string htmlContent, PdfDocument pdfDocument) { htmlContent = WrapHtmlWithPageDiv(htmlContent, pdfDocument); - return ReplaceRelativeImageUrls(htmlContent, pdfDocument); + htmlContent = ReplaceRelativeImageUrls(htmlContent, pdfDocument); + if (Options.Value.HtmlContentNormalizer == null) + { + return htmlContent; + } + + return Options.Value.HtmlContentNormalizer(htmlContent); } private string WrapHtmlWithPageDiv(string htmlContent, PdfDocument pdfDocument) @@ -96,4 +90,27 @@ public class MarkdigPdfDocumentToHtmlConverter : IDocumentToHtmlConverter x.TrimStart().StartsWith("#")); + if (titleLine == null) + { + return content; + } + + var paramValues = pdfDocument.RenderParameters.Select(x => + { + var documentParam = documentParams.Parameters.FirstOrDefault(p => p.Name == x.Key); + return $"{documentParam?.Values[x.Value] ?? x.Value}"; + }); + + var newTitle = $"{titleLine.Trim()} ({string.Join(", ", paramValues)})"; + return content.Replace(titleLine, newTitle); + } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs index 943b5d976b..de8be78ae1 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs @@ -13,6 +13,7 @@ using Volo.Abp.DependencyInjection; using Volo.Docs.Documents; using Volo.Docs.Documents.Rendering; using Volo.Docs.HtmlConverting; +using Volo.Docs.Utils; using Volo.Extensions; namespace Volo.Docs.Projects.Pdf; @@ -119,7 +120,18 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency protected virtual async Task RenderDocumentAsync(PdfDocument pdfDocument) { - return await DocumentSectionRenderer.RenderAsync(pdfDocument.Document.Content, pdfDocument.RenderParameters); + var parameters = new DocumentRenderParameters(); + if (pdfDocument.RenderParameters != null) + { + foreach (var renderParameter in pdfDocument.RenderParameters) + { + var documentParam = DocumentParams.Parameters.FirstOrDefault(p => p.Name == renderParameter.Key); + parameters.Add(renderParameter.Key, renderParameter.Value); + parameters.Add(renderParameter.Key + "_Value",documentParam?.Values[renderParameter.Value] ?? renderParameter.Value); + } + } + + return await DocumentSectionRenderer.RenderAsync(pdfDocument.Document.Content, parameters); } protected virtual async Task SetAllPdfDocumentsAsync( @@ -130,73 +142,55 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency PdfDocument parentPdfDocument = null) { var groupedCombinationsDocuments = new Dictionary>(); + foreach (var navigation in navigations) { if (navigation.IgnoreOnDownload) { continue; } + try { var pdfDocument = new PdfDocument - { + { Title = navigation.Text, - IgnoreOnOutline = navigation.Path == Options.Value.IndexPagePath + IgnoreOnOutline = navigation.Path == Options.Value.IndexPagePath, + Id = UrlHelper.IsExternalLink(navigation.Path) ? navigation.Path: null }; - - if (!navigation.Path.IsNullOrWhiteSpace() && !navigation.HasChildItems) + + if (!navigation.Path.IsNullOrWhiteSpace() && !UrlHelper.IsExternalLink(navigation.Path) && !navigation.HasChildItems) { - var document = await GetDocumentAsync(project, navigation.Path, version, languageCode); - var parameters = await DocumentSectionRenderer.GetAvailableParametersAsync(document.Content); - var parameterCombinations = GenerateAllParameterCombinations(parameters.Keys.ToList(), parameters); - var firstParameterCombination = parameterCombinations.FirstOrDefault(); - - pdfDocument.Document = document; - pdfDocument.RenderParameters = firstParameterCombination; - pdfDocument.Id = GetDocumentId(document.Name, document.Format ?? project.Format, firstParameterCombination, true); - pdfDocument.Title = GetDocumentTitle(navigation.Text, firstParameterCombination, DocumentParams); - - if(parameters.Count <= 1) + await HandleLeafDocumentAsync( + navigation, + project, + version, + languageCode, + parentPdfDocument, + groupedCombinationsDocuments, + pdfDocument + ); + } + + if (!navigation.IsInSeries) + { + if (parentPdfDocument == null) { - AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); + AllPdfDocuments.AddIfNotContains(pdfDocument); } else { - for (var i = 1; i < parameterCombinations.Count; i++) - { - var parameterCombination = parameterCombinations[i]; - var key = parameterCombination.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-"); - if (!groupedCombinationsDocuments.ContainsKey(key)) - { - groupedCombinationsDocuments[key] = []; - } - - groupedCombinationsDocuments[key].Add(new PdfDocument - { - Document = document, - Id = GetDocumentId(document.Name, document.Format ?? project.Format, parameterCombination, false), - Title = GetDocumentTitle(navigation.Text, parameterCombination, DocumentParams), - RenderParameters = parameterCombination - }); - } + parentPdfDocument.Children.AddIfNotContains(pdfDocument); } } - if (parentPdfDocument == null) - { - AllPdfDocuments.AddIfNotContains(pdfDocument); - } - else - { - parentPdfDocument.Children.AddIfNotContains(pdfDocument); - } - if (navigation.HasChildItems) { + AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); await SetAllPdfDocumentsAsync(navigation.Items, project, version, languageCode, pdfDocument); } - if (navigation == navigations.Last()) + if (!navigation.IsInSeries || navigation == navigations.Last()) { AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); } @@ -208,6 +202,53 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency } } + private async Task HandleLeafDocumentAsync( + NavigationNode navigation, + Project project, + string version, + string languageCode, + PdfDocument parentPdfDocument, + Dictionary> groupedCombinationsDocuments, + PdfDocument leafDocument) + { + var document = await GetDocumentAsync(project, navigation.Path, version, languageCode); + var parameters = await DocumentSectionRenderer.GetAvailableParametersAsync(document.Content); + var parameterCombinations = GenerateAllParameterCombinations(parameters.Keys.ToList(), parameters); + var firstCombination = parameterCombinations.FirstOrDefault(); + + leafDocument.Document = document; + leafDocument.RenderParameters = firstCombination; + leafDocument.Id = GetDocumentId(document.Name, document.Format ?? project.Format, firstCombination, true); + leafDocument.Title = GetDocumentTitle(navigation.Text, firstCombination, DocumentParams); + + if (parameterCombinations.Count <= 1) + { + AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); + return; + } + + for (var i = 0; i < parameterCombinations.Count; i++) + { + var combination = parameterCombinations[i]; + var key = string.Join("-", combination.Select(x => $"{x.Key}_{x.Value}")); + + if (!groupedCombinationsDocuments.ContainsKey(key)) + { + groupedCombinationsDocuments[key] = []; + } + + var combinationDocument = i == 0 ? leafDocument : new PdfDocument + { + Document = document, + Id = GetDocumentId(document.Name, document.Format ?? project.Format, combination, false), + Title = GetDocumentTitle(navigation.Text, combination, DocumentParams), + RenderParameters = combination + }; + + groupedCombinationsDocuments[key].Add(combinationDocument); + } + } + private void AddParameterCombinationsDocuments(PdfDocument parentPdfDocument, Dictionary> groupedCombinationsDocuments) { foreach (var combinations in groupedCombinationsDocuments) @@ -221,6 +262,8 @@ public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency parentPdfDocument.Children.AddIfNotContains(combinations.Value); } } + + groupedCombinationsDocuments.Clear(); } private async Task GetNavigationAsync(