From 056502c0fdebe9ee7a4bf0b8a8ef4e23ff211f17 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 28 Apr 2025 15:40:39 +0800 Subject: [PATCH] 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) {