Browse Source

feat(platform): add user feedback interface

pull/1039/head
colin 1 year ago
parent
commit
94effc6e49
  1. 52
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/RolePermissionDataSeedContributor.cs
  2. 5727
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/Migrations/20241114072301_Add-Feedback.Designer.cs
  3. 122
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/Migrations/20241114072301_Add-Feedback.cs
  4. 188
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/Migrations/SingleMigrationsDbContextModelSnapshot.cs
  5. 1070
      aspnet-core/migrations/LY.MicroService.Platform.EntityFrameworkCore/Migrations/20241114072749_Add-Feedback.Designer.cs
  6. 122
      aspnet-core/migrations/LY.MicroService.Platform.EntityFrameworkCore/Migrations/20241114072749_Add-Feedback.cs
  7. 188
      aspnet-core/migrations/LY.MicroService.Platform.EntityFrameworkCore/Migrations/PlatformMigrationsDbContextModelSnapshot.cs
  8. 10
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentDto.cs
  9. 14
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentGetInput.cs
  10. 6
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentTempFileCreateDto.cs
  11. 7
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentTempFileDto.cs
  12. 12
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentUploadInput.cs
  13. 10
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentCreateDto.cs
  14. 10
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentCreateOrUpdateDto.cs
  15. 8
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentDto.cs
  16. 7
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentUpdateDto.cs
  17. 17
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCreateDto.cs
  18. 13
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackDto.cs
  19. 9
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackGetListInput.cs
  20. 16
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IFeedbackAppService.cs
  21. 13
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IFeedbackAttachmentAppService.cs
  22. 17
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IFeedbackCommentAppService.cs
  23. 9
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IMyFeedbackAppService.cs
  24. 58
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Menus/IMenuAppService.cs
  25. 91
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Permissions/PlatformPermissionDefinitionProvider.cs
  26. 15
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Permissions/PlatformPermissions.cs
  27. 1
      aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/PlatformRemoteServiceConsts.cs
  28. 107
      aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/FeedbackAppService.cs
  29. 69
      aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/FeedbackAttachmentAppService.cs
  30. 10
      aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/FeedbackCommentAppService.cs
  31. 52
      aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/MyFeedbackAppService.cs
  32. 53
      aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/PlatformApplicationMappingProfile.cs
  33. 32
      aspnet-core/modules/platform/LINGYUN.Platform.Application/System/Linq/Expressions/ExpressionFuncExtensions.cs
  34. 6
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackAttachmentConsts.cs
  35. 6
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackAttachmentFile.cs
  36. 7
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackAttachmentTempFile.cs
  37. 6
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackCommentConsts.cs
  38. 6
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackConsts.cs
  39. 26
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackStatus.cs
  40. 10
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/en.json
  41. 10
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/zh-Hans.json
  42. 84
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/PlatformErrorCodes.cs
  43. 161
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/Feedback.cs
  44. 34
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackAttachment.cs
  45. 114
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackAttachmentManager.cs
  46. 16
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackAttachmentNotFoundException.cs
  47. 34
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackComment.cs
  48. 8
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackContainer.cs
  49. 25
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackStatusException.cs
  50. 21
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/IFeedbackRepository.cs
  51. 128
      aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/PlatformDomainModule.cs
  52. 56
      aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformDbContextModelBuilderExtensions.cs
  53. 3
      aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs
  54. 51
      aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/Feedbacks/EfCoreFeedbackRepository.cs
  55. 43
      aspnet-core/modules/platform/LINGYUN.Platform.HttpApi/LINGYUN/Platform/Feedbacks/FeedbackAttachmentController.cs
  56. 51
      aspnet-core/modules/platform/LINGYUN.Platform.HttpApi/LINGYUN/Platform/Feedbacks/FeedbackController.cs
  57. 27
      aspnet-core/modules/platform/LINGYUN.Platform.HttpApi/LINGYUN/Platform/Feedbacks/MyFeedbackController.cs

52
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/RolePermissionDataSeedContributor.cs

@ -0,0 +1,52 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.DataSeeder;
public class RolePermissionDataSeedContributor : IDataSeedContributor
{
public ILogger<RolePermissionDataSeedContributor> Logger { protected get; set; }
protected ICurrentTenant CurrentTenant { get; }
protected IPermissionDataSeeder PermissionDataSeeder { get; }
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
public RolePermissionDataSeedContributor(
ICurrentTenant currentTenant,
IPermissionDataSeeder permissionDataSeeder,
IPermissionDefinitionManager permissionDefinitionManager)
{
CurrentTenant = currentTenant;
PermissionDataSeeder = permissionDataSeeder;
PermissionDefinitionManager = permissionDefinitionManager;
Logger = NullLogger<RolePermissionDataSeedContributor>.Instance;
}
public async virtual Task SeedAsync(DataSeedContext context)
{
using (CurrentTenant.Change(context.TenantId))
{
Logger.LogInformation("Seeding the new tenant admin role permissions...");
var definitionPermissions = await PermissionDefinitionManager.GetPermissionsAsync();
await PermissionDataSeeder.SeedAsync(
RolePermissionValueProvider.ProviderName,
"admin",
definitionPermissions.Select(x => x.Name),
context.TenantId);
await PermissionDataSeeder.SeedAsync(
RolePermissionValueProvider.ProviderName,
"users",
new string[] { "Platform.Feedback.Create" },
context.TenantId);
}
}
}

5727
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/Migrations/20241114072301_Add-Feedback.Designer.cs

File diff suppressed because it is too large

122
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/Migrations/20241114072301_Add-Feedback.cs

@ -0,0 +1,122 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.Migrations
{
/// <inheritdoc />
public partial class AddFeedback : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppPlatformFeedbacks",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
Content = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Category = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Status = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ConcurrencyStamp = table.Column<string>(type: "varchar(40)", maxLength: 40, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true),
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
IsDeleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
DeletionTime = table.Column<DateTime>(type: "datetime(6)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppPlatformFeedbacks", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AppPlatformFeedbackAttachments",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
Name = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Url = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Size = table.Column<long>(type: "bigint", nullable: false),
FeedbackId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci")
},
constraints: table =>
{
table.PrimaryKey("PK_AppPlatformFeedbackAttachments", x => x.Id);
table.ForeignKey(
name: "FK_AppPlatformFeedbackAttachments_AppPlatformFeedbacks_Feedback~",
column: x => x.FeedbackId,
principalTable: "AppPlatformFeedbacks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AppPlatformFeedbackComments",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
Capacity = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Content = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
FeedbackId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true),
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci")
},
constraints: table =>
{
table.PrimaryKey("PK_AppPlatformFeedbackComments", x => x.Id);
table.ForeignKey(
name: "FK_AppPlatformFeedbackComments_AppPlatformFeedbacks_FeedbackId",
column: x => x.FeedbackId,
principalTable: "AppPlatformFeedbacks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_AppPlatformFeedbackAttachments_FeedbackId",
table: "AppPlatformFeedbackAttachments",
column: "FeedbackId");
migrationBuilder.CreateIndex(
name: "IX_AppPlatformFeedbackComments_FeedbackId",
table: "AppPlatformFeedbackComments",
column: "FeedbackId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppPlatformFeedbackAttachments");
migrationBuilder.DropTable(
name: "AppPlatformFeedbackComments");
migrationBuilder.DropTable(
name: "AppPlatformFeedbacks");
}
}
}

188
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/Migrations/SingleMigrationsDbContextModelSnapshot.cs

@ -1964,6 +1964,169 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.Migrations
b.ToTable("AppPlatformDataItems", (string)null); b.ToTable("AppPlatformDataItems", (string)null);
}); });
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)")
.HasColumnName("Category");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("varchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("varchar(255)")
.HasColumnName("Content");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("char(36)")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("char(36)")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime(6)")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("tinyint(1)")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime(6)")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("char(36)")
.HasColumnName("LastModifierId");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("AppPlatformFeedbacks", (string)null);
});
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("char(36)")
.HasColumnName("CreatorId");
b.Property<Guid>("FeedbackId")
.HasColumnType("char(36)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)")
.HasColumnName("Name");
b.Property<long>("Size")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)")
.HasColumnName("TenantId");
b.Property<string>("Url")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("varchar(255)")
.HasColumnName("Url");
b.HasKey("Id");
b.HasIndex("FeedbackId");
b.ToTable("AppPlatformFeedbackAttachments", (string)null);
});
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("Capacity")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)")
.HasColumnName("Capacity");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("varchar(255)")
.HasColumnName("Content");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("char(36)")
.HasColumnName("CreatorId");
b.Property<Guid>("FeedbackId")
.HasColumnType("char(36)");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime(6)")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("char(36)")
.HasColumnName("LastModifierId");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("FeedbackId");
b.ToTable("AppPlatformFeedbackComments", (string)null);
});
modelBuilder.Entity("LINGYUN.Platform.Layouts.Layout", b => modelBuilder.Entity("LINGYUN.Platform.Layouts.Layout", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -5138,6 +5301,24 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.Migrations
.IsRequired(); .IsRequired();
}); });
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b =>
{
b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null)
.WithMany("Attachments")
.HasForeignKey("FeedbackId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b =>
{
b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null)
.WithMany("Comments")
.HasForeignKey("FeedbackId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b =>
{ {
b.HasOne("LINGYUN.Platform.Packages.Package", "Package") b.HasOne("LINGYUN.Platform.Packages.Package", "Package")
@ -5445,6 +5626,13 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.Migrations
b.Navigation("Items"); b.Navigation("Items");
}); });
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b =>
{
b.Navigation("Attachments");
b.Navigation("Comments");
});
modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b =>
{ {
b.Navigation("Blobs"); b.Navigation("Blobs");

1070
aspnet-core/migrations/LY.MicroService.Platform.EntityFrameworkCore/Migrations/20241114072749_Add-Feedback.Designer.cs

File diff suppressed because it is too large

122
aspnet-core/migrations/LY.MicroService.Platform.EntityFrameworkCore/Migrations/20241114072749_Add-Feedback.cs

@ -0,0 +1,122 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Platform.EntityFrameworkCore.Migrations
{
/// <inheritdoc />
public partial class AddFeedback : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppPlatformFeedbacks",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
Content = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Category = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Status = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ConcurrencyStamp = table.Column<string>(type: "varchar(40)", maxLength: 40, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true),
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
IsDeleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
DeletionTime = table.Column<DateTime>(type: "datetime(6)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppPlatformFeedbacks", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AppPlatformFeedbackAttachments",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
Name = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Url = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Size = table.Column<long>(type: "bigint", nullable: false),
FeedbackId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci")
},
constraints: table =>
{
table.PrimaryKey("PK_AppPlatformFeedbackAttachments", x => x.Id);
table.ForeignKey(
name: "FK_AppPlatformFeedbackAttachments_AppPlatformFeedbacks_Feedback~",
column: x => x.FeedbackId,
principalTable: "AppPlatformFeedbacks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AppPlatformFeedbackComments",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
Capacity = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Content = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
FeedbackId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true),
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci")
},
constraints: table =>
{
table.PrimaryKey("PK_AppPlatformFeedbackComments", x => x.Id);
table.ForeignKey(
name: "FK_AppPlatformFeedbackComments_AppPlatformFeedbacks_FeedbackId",
column: x => x.FeedbackId,
principalTable: "AppPlatformFeedbacks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_AppPlatformFeedbackAttachments_FeedbackId",
table: "AppPlatformFeedbackAttachments",
column: "FeedbackId");
migrationBuilder.CreateIndex(
name: "IX_AppPlatformFeedbackComments_FeedbackId",
table: "AppPlatformFeedbackComments",
column: "FeedbackId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppPlatformFeedbackAttachments");
migrationBuilder.DropTable(
name: "AppPlatformFeedbackComments");
migrationBuilder.DropTable(
name: "AppPlatformFeedbacks");
}
}
}

188
aspnet-core/migrations/LY.MicroService.Platform.EntityFrameworkCore/Migrations/PlatformMigrationsDbContextModelSnapshot.cs

@ -209,6 +209,169 @@ namespace LY.MicroService.Platform.EntityFrameworkCore.Migrations
b.ToTable("AppPlatformDataItems", (string)null); b.ToTable("AppPlatformDataItems", (string)null);
}); });
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)")
.HasColumnName("Category");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("varchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("varchar(255)")
.HasColumnName("Content");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("char(36)")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("char(36)")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime(6)")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("tinyint(1)")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime(6)")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("char(36)")
.HasColumnName("LastModifierId");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("AppPlatformFeedbacks", (string)null);
});
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("char(36)")
.HasColumnName("CreatorId");
b.Property<Guid>("FeedbackId")
.HasColumnType("char(36)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)")
.HasColumnName("Name");
b.Property<long>("Size")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)")
.HasColumnName("TenantId");
b.Property<string>("Url")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("varchar(255)")
.HasColumnName("Url");
b.HasKey("Id");
b.HasIndex("FeedbackId");
b.ToTable("AppPlatformFeedbackAttachments", (string)null);
});
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("Capacity")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)")
.HasColumnName("Capacity");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("varchar(255)")
.HasColumnName("Content");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("char(36)")
.HasColumnName("CreatorId");
b.Property<Guid>("FeedbackId")
.HasColumnType("char(36)");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime(6)")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("char(36)")
.HasColumnName("LastModifierId");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("FeedbackId");
b.ToTable("AppPlatformFeedbackComments", (string)null);
});
modelBuilder.Entity("LINGYUN.Platform.Layouts.Layout", b => modelBuilder.Entity("LINGYUN.Platform.Layouts.Layout", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -853,6 +1016,24 @@ namespace LY.MicroService.Platform.EntityFrameworkCore.Migrations
.IsRequired(); .IsRequired();
}); });
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b =>
{
b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null)
.WithMany("Attachments")
.HasForeignKey("FeedbackId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b =>
{
b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null)
.WithMany("Comments")
.HasForeignKey("FeedbackId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b =>
{ {
b.HasOne("LINGYUN.Platform.Packages.Package", "Package") b.HasOne("LINGYUN.Platform.Packages.Package", "Package")
@ -869,6 +1050,13 @@ namespace LY.MicroService.Platform.EntityFrameworkCore.Migrations
b.Navigation("Items"); b.Navigation("Items");
}); });
modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b =>
{
b.Navigation("Attachments");
b.Navigation("Comments");
});
modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b =>
{ {
b.Navigation("Blobs"); b.Navigation("Blobs");

10
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentDto.cs

@ -0,0 +1,10 @@
using System;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentDto : CreationAuditedEntityDto<Guid>
{
public string Name { get; set; }
public string Url { get; set; }
public long Size { get; set; }
}

14
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentGetInput.cs

@ -0,0 +1,14 @@
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentGetInput
{
[Required]
public Guid FeedbackId { get; set; }
[Required]
[DynamicStringLength(typeof(FeedbackAttachmentConsts), nameof(FeedbackAttachmentConsts.MaxNameLength))]
public string Name { get; set; }
}

6
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentTempFileCreateDto.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentTempFileCreateDto
{
public string Path { get; set; }
public string Id { get; set; }
}

7
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentTempFileDto.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentTempFileDto
{
public string Path { get; set; }
public string Id { get; set; }
public long Size { get; set; }
}

12
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackAttachmentUploadInput.cs

@ -0,0 +1,12 @@
using Volo.Abp.Auditing;
using Volo.Abp.Content;
using Volo.Abp.Validation;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentUploadInput
{
[DisableAuditing]
[DisableValidation]
public IRemoteStreamContent File { get; set; }
}

10
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentCreateDto.cs

@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackCommentCreateDto : FeedbackCommentCreateOrUpdateDto
{
[Required]
[DynamicStringLength(typeof(FeedbackCommentConsts), nameof(FeedbackCommentConsts.MaxCapacityLength))]
public string Capacity { get; set; }
}

10
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentCreateOrUpdateDto.cs

@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
namespace LINGYUN.Platform.Feedbacks;
public abstract class FeedbackCommentCreateOrUpdateDto
{
[Required]
[DynamicStringLength(typeof(FeedbackCommentConsts), nameof(FeedbackCommentConsts.MaxContentLength))]
public string Content { get; set; }
}

8
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentDto.cs

@ -0,0 +1,8 @@
using System;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackCommentDto : AuditedEntityDto<Guid>
{
public string Content { get; set; }
}

7
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCommentUpdateDto.cs

@ -0,0 +1,7 @@
using Volo.Abp.Domain.Entities;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackCommentUpdateDto : FeedbackCommentCreateOrUpdateDto, IHasConcurrencyStamp
{
public string ConcurrencyStamp { get; set; }
}

17
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackCreateDto.cs

@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackCreateDto
{
[Required]
[DynamicStringLength(typeof(FeedbackConsts), nameof(FeedbackConsts.MaxContentLength))]
public string Content { get; set; }
[Required]
[DynamicStringLength(typeof(FeedbackConsts), nameof(FeedbackConsts.MaxCategoryLength))]
public string Category { get; set; }
public List<FeedbackAttachmentTempFileCreateDto> Attachments { get; set; }
}

13
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackDto.cs

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackDto : ExtensibleAuditedEntityDto<Guid>
{
public string Content { get; set; }
public string Category { get; set; }
public FeedbackStatus Status { get; set; }
public List<FeedbackCommentDto> Comments { get; set; }
public List<FeedbackAttachmentDto> Attachments { get; set; }
}

9
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/Dto/FeedbackGetListInput.cs

@ -0,0 +1,9 @@
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackGetListInput : PagedAndSortedResultRequestDto
{
public string Filter { get; set; }
public string Category { get; set; }
public FeedbackStatus? Status { get; set; }
}

16
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IFeedbackAppService.cs

@ -0,0 +1,16 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace LINGYUN.Platform.Feedbacks;
public interface IFeedbackAppService : IApplicationService
{
Task<FeedbackDto> GetAsync(Guid id);
Task<FeedbackDto> CreateAsync(FeedbackCreateDto input);
Task DeleteAsync(Guid id);
Task<PagedResultDto<FeedbackDto>> GetListAsync(FeedbackGetListInput input);
}

13
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IFeedbackAttachmentAppService.cs

@ -0,0 +1,13 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace LINGYUN.Platform.Feedbacks;
public interface IFeedbackAttachmentAppService : IApplicationService
{
Task<FeedbackAttachmentTempFileDto> UploadAsync(FeedbackAttachmentUploadInput input);
Task<IRemoteStreamContent> GetAsync(FeedbackAttachmentGetInput input);
Task DeleteAsync(FeedbackAttachmentGetInput input);
}

17
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IFeedbackCommentAppService.cs

@ -0,0 +1,17 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Platform.Feedbacks;
public interface IFeedbackCommentAppService : IApplicationService
{
Task<FeedbackCommentDto> ProgressAsync(FeedbackCommentCreateDto input);
Task<FeedbackCommentDto> CloseAsync(FeedbackCommentCreateDto input);
Task<FeedbackCommentDto> ResolveAsync(FeedbackCommentCreateDto input);
Task<FeedbackCommentDto> UpdateAsync(Guid id, FeedbackCommentUpdateDto input);
Task<FeedbackCommentDto> DeleteAsync(Guid id);
}

9
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Feedbacks/IMyFeedbackAppService.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace LINGYUN.Platform.Feedbacks;
public interface IMyFeedbackAppService : IApplicationService
{
Task<PagedResultDto<FeedbackDto>> GetMyFeedbacksAsync(FeedbackGetListInput input);
}

58
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Menus/IMenuAppService.cs

@ -1,31 +1,31 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
namespace LINGYUN.Platform.Menus; namespace LINGYUN.Platform.Menus;
public interface IMenuAppService : public interface IMenuAppService :
ICrudAppService< ICrudAppService<
MenuDto, MenuDto,
Guid, Guid,
MenuGetListInput, MenuGetListInput,
MenuCreateDto, MenuCreateDto,
MenuUpdateDto> MenuUpdateDto>
{ {
Task<ListResultDto<MenuDto>> GetAllAsync(MenuGetAllInput input); Task<ListResultDto<MenuDto>> GetAllAsync(MenuGetAllInput input);
Task<ListResultDto<MenuDto>> GetUserMenuListAsync(MenuGetByUserInput input); Task<ListResultDto<MenuDto>> GetUserMenuListAsync(MenuGetByUserInput input);
Task<ListResultDto<MenuDto>> GetRoleMenuListAsync(MenuGetByRoleInput input); Task<ListResultDto<MenuDto>> GetRoleMenuListAsync(MenuGetByRoleInput input);
Task SetUserMenusAsync(UserMenuInput input); Task SetUserMenusAsync(UserMenuInput input);
Task SetUserStartupAsync(Guid id, UserMenuStartupInput input); Task SetUserStartupAsync(Guid id, UserMenuStartupInput input);
Task SetRoleMenusAsync(RoleMenuInput input); Task SetRoleMenusAsync(RoleMenuInput input);
Task SetRoleStartupAsync(Guid id, RoleMenuStartupInput input); Task SetRoleStartupAsync(Guid id, RoleMenuStartupInput input);
Task<ListResultDto<MenuDto>> GetCurrentUserMenuListAsync(GetMenuInput input); Task<ListResultDto<MenuDto>> GetCurrentUserMenuListAsync(GetMenuInput input);
} }

91
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Permissions/PlatformPermissionDefinitionProvider.cs

@ -1,44 +1,51 @@
using LINGYUN.Platform.Localization; using LINGYUN.Platform.Localization;
using Volo.Abp.Authorization.Permissions; using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization; using Volo.Abp.Localization;
namespace LINGYUN.Platform.Permissions; namespace LINGYUN.Platform.Permissions;
public class PlatformPermissionDefinitionProvider : PermissionDefinitionProvider public class PlatformPermissionDefinitionProvider : PermissionDefinitionProvider
{ {
public override void Define(IPermissionDefinitionContext context) public override void Define(IPermissionDefinitionContext context)
{ {
var platform = context.AddGroup(PlatformPermissions.GroupName, L("Permission:Platform")); var platform = context.AddGroup(PlatformPermissions.GroupName, L("Permission:Platform"));
var dataDictionary = platform.AddPermission(PlatformPermissions.DataDictionary.Default, L("Permission:DataDictionary")); var dataDictionary = platform.AddPermission(PlatformPermissions.DataDictionary.Default, L("Permission:DataDictionary"));
dataDictionary.AddChild(PlatformPermissions.DataDictionary.Create, L("Permission:Create")); dataDictionary.AddChild(PlatformPermissions.DataDictionary.Create, L("Permission:Create"));
dataDictionary.AddChild(PlatformPermissions.DataDictionary.Update, L("Permission:Update")); dataDictionary.AddChild(PlatformPermissions.DataDictionary.Update, L("Permission:Update"));
dataDictionary.AddChild(PlatformPermissions.DataDictionary.Move, L("Permission:Move")); dataDictionary.AddChild(PlatformPermissions.DataDictionary.Move, L("Permission:Move"));
dataDictionary.AddChild(PlatformPermissions.DataDictionary.Delete, L("Permission:Delete")); dataDictionary.AddChild(PlatformPermissions.DataDictionary.Delete, L("Permission:Delete"));
dataDictionary.AddChild(PlatformPermissions.DataDictionary.ManageItems, L("Permission:ManageItems")); dataDictionary.AddChild(PlatformPermissions.DataDictionary.ManageItems, L("Permission:ManageItems"));
var layout = platform.AddPermission(PlatformPermissions.Layout.Default, L("Permission:Layout")); var layout = platform.AddPermission(PlatformPermissions.Layout.Default, L("Permission:Layout"));
layout.AddChild(PlatformPermissions.Layout.Create, L("Permission:Create")); layout.AddChild(PlatformPermissions.Layout.Create, L("Permission:Create"));
layout.AddChild(PlatformPermissions.Layout.Update, L("Permission:Update")); layout.AddChild(PlatformPermissions.Layout.Update, L("Permission:Update"));
layout.AddChild(PlatformPermissions.Layout.Delete, L("Permission:Delete")); layout.AddChild(PlatformPermissions.Layout.Delete, L("Permission:Delete"));
var menu = platform.AddPermission(PlatformPermissions.Menu.Default, L("Permission:Menu")); var menu = platform.AddPermission(PlatformPermissions.Menu.Default, L("Permission:Menu"));
menu.AddChild(PlatformPermissions.Menu.Create, L("Permission:Create")); menu.AddChild(PlatformPermissions.Menu.Create, L("Permission:Create"));
menu.AddChild(PlatformPermissions.Menu.Update, L("Permission:Update")); menu.AddChild(PlatformPermissions.Menu.Update, L("Permission:Update"));
menu.AddChild(PlatformPermissions.Menu.Delete, L("Permission:Delete")); menu.AddChild(PlatformPermissions.Menu.Delete, L("Permission:Delete"));
menu.AddChild(PlatformPermissions.Menu.ManageRoles, L("Permission:ManageRoleMenus")); menu.AddChild(PlatformPermissions.Menu.ManageRoles, L("Permission:ManageRoleMenus"));
menu.AddChild(PlatformPermissions.Menu.ManageUsers, L("Permission:ManageUserMenus")); menu.AddChild(PlatformPermissions.Menu.ManageUsers, L("Permission:ManageUserMenus"));
menu.AddChild(PlatformPermissions.Menu.ManageUserFavorites, L("Permission:ManageUserFavoriteMenus")); menu.AddChild(PlatformPermissions.Menu.ManageUserFavorites, L("Permission:ManageUserFavoriteMenus"));
var package = platform.AddPermission(PlatformPermissions.Package.Default, L("Permission:Package")); var package = platform.AddPermission(PlatformPermissions.Package.Default, L("Permission:Package"));
package.AddChild(PlatformPermissions.Package.Create, L("Permission:Create")); package.AddChild(PlatformPermissions.Package.Create, L("Permission:Create"));
package.AddChild(PlatformPermissions.Package.Update, L("Permission:Update")); package.AddChild(PlatformPermissions.Package.Update, L("Permission:Update"));
package.AddChild(PlatformPermissions.Package.Delete, L("Permission:Delete")); package.AddChild(PlatformPermissions.Package.Delete, L("Permission:Delete"));
package.AddChild(PlatformPermissions.Package.ManageBlobs, L("Permission:ManageBlobs")); package.AddChild(PlatformPermissions.Package.ManageBlobs, L("Permission:ManageBlobs"));
}
var feedback = platform.AddPermission(PlatformPermissions.Feedback.Default, L("Permission:Feedback"));
private static LocalizableString L(string name) feedback.AddChild(PlatformPermissions.Feedback.Create, L("Permission:Create"));
{ feedback.AddChild(PlatformPermissions.Feedback.Update, L("Permission:Update"));
return LocalizableString.Create<PlatformResource>(name); feedback.AddChild(PlatformPermissions.Feedback.Delete, L("Permission:Delete"));
} feedback.AddChild(PlatformPermissions.Feedback.ManageAttachments, L("Permission:ManageAttachments"));
} feedback.AddChild(PlatformPermissions.Feedback.ManageComments, L("Permission:ManageComments"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<PlatformResource>(name);
}
}

15
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/Permissions/PlatformPermissions.cs

@ -98,6 +98,21 @@ public static class PlatformPermissions
public const string ManageBlobs = Default + ".ManageBlobs"; public const string ManageBlobs = Default + ".ManageBlobs";
} }
public class Feedback
{
public const string Default = GroupName + ".Feedback";
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
public const string ManageComments = Default + ".ManageComments";
public const string ManageAttachments = Default + ".ManageAttachments";
}
public static string[] GetAll() public static string[] GetAll()
{ {
return ReflectionHelper.GetPublicConstantsRecursively(typeof(PlatformPermissions)); return ReflectionHelper.GetPublicConstantsRecursively(typeof(PlatformPermissions));

1
aspnet-core/modules/platform/LINGYUN.Platform.Application.Contracts/LINGYUN/Platform/PlatformRemoteServiceConsts.cs

@ -3,4 +3,5 @@
public static class PlatformRemoteServiceConsts public static class PlatformRemoteServiceConsts
{ {
public const string RemoteServiceName = "Platform"; public const string RemoteServiceName = "Platform";
public const string ModuleName = "platform";
} }

107
aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/FeedbackAppService.cs

@ -0,0 +1,107 @@
using LINGYUN.Platform.Permissions;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Platform.Feedbacks;
[Authorize(PlatformPermissions.Feedback.Default)]
public class FeedbackAppService : PlatformApplicationServiceBase, IFeedbackAppService
{
private readonly FeedbackAttachmentManager _attachmentManager;
private readonly IFeedbackRepository _feedbackRepository;
public FeedbackAppService(
FeedbackAttachmentManager attachmentManager,
IFeedbackRepository feedbackRepository)
{
_attachmentManager = attachmentManager;
_feedbackRepository = feedbackRepository;
}
[Authorize(PlatformPermissions.Feedback.Create)]
public async virtual Task<FeedbackDto> CreateAsync(FeedbackCreateDto input)
{
var feedback = new Feedback(
GuidGenerator.Create(),
input.Category,
input.Content,
FeedbackStatus.Created,
CurrentTenant.Id);
if (input.Attachments != null)
{
foreach (var attachment in input.Attachments)
{
var attachmentFile = await _attachmentManager.CopyFromTempAsync(
feedback,
attachment.Path,
attachment.Id);
feedback.AddAttachment(
GuidGenerator,
attachmentFile.Name,
$"/api/platform/feedbacks/{feedback.Id}/attachments/{attachmentFile.Name}",
attachmentFile.Size);
}
}
feedback = await _feedbackRepository.InsertAsync(feedback);
await CurrentUnitOfWork.SaveChangesAsync();
return ObjectMapper.Map<Feedback, FeedbackDto>(feedback);
}
[Authorize(PlatformPermissions.Feedback.Delete)]
public async Task DeleteAsync(Guid id)
{
var feedback = await _feedbackRepository.GetAsync(id);
await _feedbackRepository.DeleteAsync(feedback);
await CurrentUnitOfWork.SaveChangesAsync();
}
[Authorize(PlatformPermissions.Feedback.Default)]
public async virtual Task<FeedbackDto> GetAsync(Guid id)
{
var feedback = await _feedbackRepository.GetAsync(id);
return ObjectMapper.Map<Feedback, FeedbackDto>(feedback);
}
public async virtual Task<PagedResultDto<FeedbackDto>> GetListAsync(FeedbackGetListInput input)
{
var specification = new FeedbackGetListSpecification(input);
var totalCount = await _feedbackRepository.GetCountAsync(specification);
var feedbacks = await _feedbackRepository.GetListAsync(specification,
input.Sorting, input.MaxResultCount, input.SkipCount);
return new PagedResultDto<FeedbackDto>(totalCount,
ObjectMapper.Map<List<Feedback>, List<FeedbackDto>>(feedbacks));
}
internal class FeedbackGetListSpecification : Volo.Abp.Specifications.Specification<Feedback>
{
protected FeedbackGetListInput Input { get; }
public FeedbackGetListSpecification(FeedbackGetListInput input)
{
Input = input;
}
public override Expression<Func<Feedback, bool>> ToExpression()
{
Expression<Func<Feedback, bool>> expression = _ => true;
return expression
.AndIf(Input.Status.HasValue, x => x.Status == Input.Status)
.AndIf(!Input.Category.IsNullOrWhiteSpace(), x => x.Category == Input.Category)
.AndIf(!Input.Filter.IsNullOrWhiteSpace(), x => x.Category.Contains(Input.Filter) ||
x.Content.Contains(Input.Filter));
}
}
}

69
aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/FeedbackAttachmentAppService.cs

@ -0,0 +1,69 @@
using LINGYUN.Platform.Permissions;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Threading.Tasks;
using Volo.Abp.Content;
namespace LINGYUN.Platform.Feedbacks;
[Authorize(PlatformPermissions.Feedback.Default)]
public class FeedbackAttachmentAppService : PlatformApplicationServiceBase, IFeedbackAttachmentAppService
{
private readonly IFeedbackRepository _feedbackRepository;
private readonly FeedbackAttachmentManager _feedbackAttachmentManager;
public FeedbackAttachmentAppService(
IFeedbackRepository feedbackRepository,
FeedbackAttachmentManager feedbackAttachmentManager)
{
_feedbackRepository = feedbackRepository;
_feedbackAttachmentManager = feedbackAttachmentManager;
}
public async virtual Task<FeedbackAttachmentTempFileDto> UploadAsync(FeedbackAttachmentUploadInput input)
{
var stream = input.File.GetStream();
var tmpFile = await _feedbackAttachmentManager.SaveToTempAsync(stream);
return new FeedbackAttachmentTempFileDto
{
Size = tmpFile.Size,
Path = tmpFile.Path,
Id = tmpFile.Id,
};
}
public async virtual Task<IRemoteStreamContent> GetAsync(FeedbackAttachmentGetInput input)
{
var attachment = await GetFeedbackAttachmentAsync(input);
var stream = await _feedbackAttachmentManager.DownloadAsync(attachment);
return new RemoteStreamContent(stream, attachment.Name);
}
public async virtual Task DeleteAsync(FeedbackAttachmentGetInput input)
{
var feedback = await _feedbackRepository.GetAsync(input.FeedbackId);
if (feedback.CreatorId != CurrentUser.Id)
{
await AuthorizationService.CheckAsync(PlatformPermissions.Feedback.ManageAttachments);
}
var attachment = feedback.FindAttachment(input.Name);
feedback.RemoveAttachment(attachment.Name);
await CurrentUnitOfWork.SaveChangesAsync();
await _feedbackAttachmentManager.DeleteAsync(attachment);
}
protected async virtual Task<FeedbackAttachment> GetFeedbackAttachmentAsync(FeedbackAttachmentGetInput input)
{
var feedback = await _feedbackRepository.GetAsync(input.FeedbackId);
var attachment = feedback.FindAttachment(input.Name);
return attachment ?? throw new FeedbackAttachmentNotFoundException(input.Name);
}
}

10
aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/FeedbackCommentAppService.cs

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackCommentAppService
{
}

52
aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/Feedbacks/MyFeedbackAppService.cs

@ -0,0 +1,52 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Users;
using static LINGYUN.Platform.Feedbacks.FeedbackAppService;
namespace LINGYUN.Platform.Feedbacks;
[Authorize]
public class MyFeedbackAppService : PlatformApplicationServiceBase, IMyFeedbackAppService
{
private readonly IFeedbackRepository _feedbackRepository;
public MyFeedbackAppService(IFeedbackRepository feedbackRepository)
{
_feedbackRepository = feedbackRepository;
}
public async virtual Task<PagedResultDto<FeedbackDto>> GetMyFeedbacksAsync(FeedbackGetListInput input)
{
var specification = new FeedbackGetListByUserSpecification(CurrentUser.GetId(), input);
var totalCount = await _feedbackRepository.GetCountAsync(specification);
var feedbacks = await _feedbackRepository.GetListAsync(specification,
input.Sorting, input.MaxResultCount, input.SkipCount);
return new PagedResultDto<FeedbackDto>(totalCount,
ObjectMapper.Map<List<Feedback>, List<FeedbackDto>>(feedbacks));
}
private class FeedbackGetListByUserSpecification : FeedbackGetListSpecification
{
protected Guid UserId { get; }
public FeedbackGetListByUserSpecification(
Guid userId,
FeedbackGetListInput input)
: base(input)
{
UserId = userId;
}
public override Expression<Func<Feedback, bool>> ToExpression()
{
var expression = base.ToExpression();
return expression.And(x => x.CreatorId == UserId);
}
}
}

53
aspnet-core/modules/platform/LINGYUN.Platform.Application/LINGYUN/Platform/PlatformApplicationMappingProfile.cs

@ -1,25 +1,30 @@
using AutoMapper; using AutoMapper;
using LINGYUN.Platform.Datas; using LINGYUN.Platform.Datas;
using LINGYUN.Platform.Layouts; using LINGYUN.Platform.Feedbacks;
using LINGYUN.Platform.Menus; using LINGYUN.Platform.Layouts;
using LINGYUN.Platform.Menus;
using LINGYUN.Platform.Packages; using LINGYUN.Platform.Packages;
namespace LINGYUN.Platform; namespace LINGYUN.Platform;
public class PlatformApplicationMappingProfile : Profile public class PlatformApplicationMappingProfile : Profile
{ {
public PlatformApplicationMappingProfile() public PlatformApplicationMappingProfile()
{ {
CreateMap<PackageBlob, PackageBlobDto>(); CreateMap<PackageBlob, PackageBlobDto>();
CreateMap<Package, PackageDto>(); CreateMap<Package, PackageDto>();
CreateMap<DataItem, DataItemDto>(); CreateMap<DataItem, DataItemDto>();
CreateMap<Data, DataDto>(); CreateMap<Data, DataDto>();
CreateMap<Menu, MenuDto>() CreateMap<Menu, MenuDto>()
.ForMember(dto => dto.Meta, map => map.MapFrom(src => src.ExtraProperties)) .ForMember(dto => dto.Meta, map => map.MapFrom(src => src.ExtraProperties))
.ForMember(dto => dto.Startup, map => map.Ignore()); .ForMember(dto => dto.Startup, map => map.Ignore());
CreateMap<Layout, LayoutDto>() CreateMap<Layout, LayoutDto>()
.ForMember(dto => dto.Meta, map => map.MapFrom(src => src.ExtraProperties)); .ForMember(dto => dto.Meta, map => map.MapFrom(src => src.ExtraProperties));
CreateMap<UserFavoriteMenu, UserFavoriteMenuDto>(); CreateMap<UserFavoriteMenu, UserFavoriteMenuDto>();
}
} CreateMap<Feedback, FeedbackDto>();
CreateMap<FeedbackComment, FeedbackCommentDto>();
CreateMap<FeedbackAttachment, FeedbackAttachmentDto>();
}
}

32
aspnet-core/modules/platform/LINGYUN.Platform.Application/System/Linq/Expressions/ExpressionFuncExtensions.cs

@ -0,0 +1,32 @@
using Volo.Abp.Specifications;
namespace System.Linq.Expressions;
internal static class ExpressionFuncExtensions
{
public static Expression<Func<T, bool>> AndIf<T>(
this Expression<Func<T, bool>> first,
bool condition,
Expression<Func<T, bool>> second)
{
if (condition)
{
return ExpressionFuncExtender.And(first, second);
}
return first;
}
public static Expression<Func<T, bool>> OrIf<T>(
this Expression<Func<T, bool>> first,
bool condition,
Expression<Func<T, bool>> second)
{
if (condition)
{
return ExpressionFuncExtender.Or(first, second);
}
return first;
}
}

6
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackAttachmentConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Platform.Feedbacks;
public static class FeedbackAttachmentConsts
{
public static int MaxNameLength { get; set; } = 64;
public static int MaxUrlLength { get; set; } = 255;
}

6
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackAttachmentFile.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentFile(string name, long size)
{
public string Name { get; } = name;
public long Size { get; } = size;
}

7
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackAttachmentTempFile.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentTempFile
{
public string Path { get; set; }
public string Id { get; set; }
public long Size { get; set; }
}

6
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackCommentConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Platform.Feedbacks;
public static class FeedbackCommentConsts
{
public static int MaxContentLength { get; set; } = 255;
public static int MaxCapacityLength { get; set; } = 64;
}

6
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Platform.Feedbacks;
public static class FeedbackConsts
{
public static int MaxCategoryLength { get; set; } = 64;
public static int MaxContentLength { get; set; } = 255;
}

26
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Feedbacks/FeedbackStatus.cs

@ -0,0 +1,26 @@
using System.ComponentModel;
namespace LINGYUN.Platform.Feedbacks;
public enum FeedbackStatus
{
/// <summary>
/// 新增
/// </summary>
[Description("FeedbackStatus:Created")]
Created = 1,
/// <summary>
/// 处理中
/// </summary>
[Description("FeedbackStatus:InProgress")]
InProgress = 2,
/// <summary>
/// 已关闭
/// </summary>
[Description("FeedbackStatus:Closed")]
Closed = 3,
/// <summary>
/// 已解决
/// </summary>
[Description("FeedbackStatus:Resolved")]
Resolved = 4
}

10
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/en.json

@ -10,6 +10,10 @@
"Platform:03001": "The metadata format does not match!", "Platform:03001": "The metadata format does not match!",
"Platform:04400": "The user favorites the menu repeatedly!", "Platform:04400": "The user favorites the menu repeatedly!",
"Platform:04404": "User Favorites menu not found!", "Platform:04404": "User Favorites menu not found!",
"Platform:05101": "Unable to comment on issues in {Status} status!",
"Platform:05102": "Cannot add duplicate attachments {Name}!",
"Platform:05103": "User feedback: Attachment named {Name} not found!",
"Platform:05104": "Attachment {Name} is invalid, please upload again!",
"UploadFileSizeBeyondLimit": "Upload file size cannot exceed {0} MB!", "UploadFileSizeBeyondLimit": "Upload file size cannot exceed {0} MB!",
"NotAllowedFileExtensionName": "Not allowed file extension: {0}!", "NotAllowedFileExtensionName": "Not allowed file extension: {0}!",
"DisplayName:VersionFileLimitLength": "File limit size", "DisplayName:VersionFileLimitLength": "File limit size",
@ -75,6 +79,10 @@
"DataItemNotFound": "There is no data dictionary entry named {0}!", "DataItemNotFound": "There is no data dictionary entry named {0}!",
"UnableRemoveHasChildNode": "Current data dictionary exists child node, cannot delete!", "UnableRemoveHasChildNode": "Current data dictionary exists child node, cannot delete!",
"DuplicateLayout": "A layout named {0} already exists!", "DuplicateLayout": "A layout named {0} already exists!",
"Packages": "Packages" "Packages": "Packages",
"FeedbackStatus:Created": "Created",
"FeedbackStatus:InProgress": "Pending",
"FeedbackStatus:Closed": "Closed",
"FeedbackStatus:Resolved": "Resolved"
} }
} }

10
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/zh-Hans.json

@ -10,6 +10,10 @@
"Platform:03001": "元数据格式不匹配!", "Platform:03001": "元数据格式不匹配!",
"Platform:04400": "用户重复收藏菜单!", "Platform:04400": "用户重复收藏菜单!",
"Platform:04404": "用户收藏菜单未找到!", "Platform:04404": "用户收藏菜单未找到!",
"Platform:05101": "无法对处于{Status}状态的问题进行评论!",
"Platform:05102": "不能添加重复的附件 {Name}!",
"Platform:05103": "用户反馈未找到名为 {Name} 的附件!",
"Platform:05104": "附件 {Name} 已失效, 请重新上传!",
"UploadFileSizeBeyondLimit": "上传文件大小不能超过 {0} MB!", "UploadFileSizeBeyondLimit": "上传文件大小不能超过 {0} MB!",
"NotAllowedFileExtensionName": "不被允许的文件扩展名: {0}!", "NotAllowedFileExtensionName": "不被允许的文件扩展名: {0}!",
"DisplayName:VersionFileLimitLength": "文件限制大小", "DisplayName:VersionFileLimitLength": "文件限制大小",
@ -75,6 +79,10 @@
"DataItemNotFound": "不存在名为 {0} 的数据字典项!", "DataItemNotFound": "不存在名为 {0} 的数据字典项!",
"UnableRemoveHasChildNode": "当前数据字典存在子节点,无法删除!", "UnableRemoveHasChildNode": "当前数据字典存在子节点,无法删除!",
"DuplicateLayout": "已经存在名为 {0} 的布局!", "DuplicateLayout": "已经存在名为 {0} 的布局!",
"Packages": "包列表" "Packages": "包列表",
"FeedbackStatus:Created": "新增",
"FeedbackStatus:InProgress": "处理中",
"FeedbackStatus:Closed": "已关闭",
"FeedbackStatus:Resolved": "已解决"
} }
} }

84
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/PlatformErrorCodes.cs

@ -1,40 +1,56 @@
namespace LINGYUN.Platform; namespace LINGYUN.Platform;
public static class PlatformErrorCodes public static class PlatformErrorCodes
{ {
private const string Namespace = "Platform"; private const string Namespace = "Platform";
public const string VersionFileNotFound = Namespace + ":01404"; public const string VersionFileNotFound = Namespace + ":01404";
/// <summary> /// <summary>
/// 包版本不能降级 /// 包版本不能降级
/// </summary> /// </summary>
public const string PackageVersionDegraded = Namespace + ":01403"; public const string PackageVersionDegraded = Namespace + ":01403";
/// <summary> /// <summary>
/// 同级菜单已经存在 /// 同级菜单已经存在
/// </summary> /// </summary>
public const string DuplicateMenu = Namespace + ":02001"; public const string DuplicateMenu = Namespace + ":02001";
/// <summary> /// <summary>
/// 不能删除拥有子菜单的节点 /// 不能删除拥有子菜单的节点
/// </summary> /// </summary>
public const string DeleteMenuHaveChildren = Namespace + ":02002"; public const string DeleteMenuHaveChildren = Namespace + ":02002";
/// <summary> /// <summary>
/// 菜单层级已达到最大值 /// 菜单层级已达到最大值
/// </summary> /// </summary>
public const string MenuAchieveMaxDepth = Namespace + ":02003"; public const string MenuAchieveMaxDepth = Namespace + ":02003";
/// <summary> /// <summary>
/// 菜单元数据缺少必要的元素 /// 菜单元数据缺少必要的元素
/// </summary> /// </summary>
public const string MenuMissingMetadata = Namespace + ":02101"; public const string MenuMissingMetadata = Namespace + ":02101";
/// <summary> /// <summary>
/// 元数据格式不匹配 /// 元数据格式不匹配
/// </summary> /// </summary>
public const string MetaFormatMissMatch = Namespace + ":03001"; public const string MetaFormatMissMatch = Namespace + ":03001";
/// <summary> /// <summary>
/// 用户重复收藏菜单 /// 用户重复收藏菜单
/// </summary> /// </summary>
public const string UserDuplicateFavoriteMenu = Namespace + ":04400"; public const string UserDuplicateFavoriteMenu = Namespace + ":04400";
/// <summary> /// <summary>
/// 用户收藏菜单未找到 /// 用户收藏菜单未找到
/// </summary> /// </summary>
public const string UserFavoriteMenuNotFound = Namespace + ":04404"; public const string UserFavoriteMenuNotFound = Namespace + ":04404";
} /// <summary>
/// 无法对处于{Status}状态的问题进行评论
/// </summary>
public const string UnableFeedbackCommentInStatus = Namespace + ":05101";
/// <summary>
/// 不能添加重复的附件 {Name}!
/// </summary>
public const string DuplicateFeedbackAttachment = Namespace + ":05102";
/// <summary>
/// 用户反馈未找到名为 {Name} 的附件!
/// </summary>
public const string FeedackAttachmentNotFound = Namespace + ":05103";
/// <summary>
/// 附件 {Name} 已失效, 请重新上传!
/// </summary>
public const string FeedackAttachmentLoseEffectiveness = Namespace + ":05104";
}

161
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/Feedback.cs

@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Platform.Feedbacks;
public class Feedback : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual string Content { get; set; }
public virtual string Category { get; protected set; }
public virtual FeedbackStatus Status { get; protected set; }
public virtual ICollection<FeedbackComment> Comments { get; protected set; }
public virtual ICollection<FeedbackAttachment> Attachments { get; protected set; }
protected Feedback()
{
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
Comments = new Collection<FeedbackComment>();
Attachments = new Collection<FeedbackAttachment>();
}
public Feedback(
Guid id,
string category,
string content,
FeedbackStatus status,
Guid? tenantId = null)
: base(id)
{
Category = Check.NotNullOrWhiteSpace(category, nameof(category), FeedbackConsts.MaxCategoryLength);
Content = Check.NotNullOrWhiteSpace(content, nameof(content), FeedbackConsts.MaxContentLength);
Status = status;
TenantId = tenantId;
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
Comments = new Collection<FeedbackComment>();
Attachments = new Collection<FeedbackAttachment>();
}
public FeedbackAttachment AddAttachment(
IGuidGenerator guidGenerator,
string name,
string url,
long size)
{
if (FindAttachment(name) != null)
{
throw new BusinessException(PlatformErrorCodes.DuplicateFeedbackAttachment)
.WithData("Name", name);
}
var attachment = new FeedbackAttachment(
guidGenerator.Create(),
Id,
name,
url,
size,
TenantId);
Attachments.Add(attachment);
return attachment;
}
public FeedbackAttachment FindAttachment(string name)
{
return Attachments.FirstOrDefault(x => x.Name == name);
}
public Feedback RemoveAttachment(string name)
{
Attachments.RemoveAll(x => x.Name == name);
return this;
}
public FeedbackComment Progress(
IGuidGenerator generator,
string capacity,
string content)
{
ValidateStatus();
var comment = new FeedbackComment(
generator.Create(),
Id,
capacity,
content,
TenantId);
Comments.Add(comment);
Status = FeedbackStatus.InProgress;
return comment;
}
public FeedbackComment Close(
IGuidGenerator generator,
string capacity,
string content)
{
ValidateStatus();
var comment = new FeedbackComment(
generator.Create(),
Id,
capacity,
content,
TenantId);
Comments.Add(comment);
Status = FeedbackStatus.Closed;
return comment;
}
public FeedbackComment Resolve(
IGuidGenerator generator,
string capacity,
string content)
{
ValidateStatus();
var comment = new FeedbackComment(
generator.Create(),
Id,
capacity,
content,
TenantId);
Comments.Add(comment);
Status = FeedbackStatus.Resolved;
return comment;
}
public Feedback ValidateStatus()
{
if (Status == FeedbackStatus.Closed)
{
throw new FeedbackStatusException(PlatformErrorCodes.UnableFeedbackCommentInStatus, FeedbackStatus.Closed);
}
if (Status == FeedbackStatus.Resolved)
{
throw new FeedbackStatusException(PlatformErrorCodes.UnableFeedbackCommentInStatus, FeedbackStatus.Resolved);
}
return this;
}
}

34
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackAttachment.cs

@ -0,0 +1,34 @@
using System;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachment : CreationAuditedEntity<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string Url { get; protected set; }
public virtual long Size { get; protected set; }
public virtual Guid FeedbackId { get; protected set; }
protected FeedbackAttachment()
{
}
public FeedbackAttachment(
Guid id,
Guid feedbackId,
string name,
string url,
long size,
Guid? tenantId)
:base(id)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name), FeedbackAttachmentConsts.MaxNameLength);
Url = Check.NotNullOrWhiteSpace(url, nameof(url), FeedbackAttachmentConsts.MaxUrlLength);
Size = size;
FeedbackId = feedbackId;
TenantId = tenantId;
}
}

114
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackAttachmentManager.cs

@ -0,0 +1,114 @@
using System.IO;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.BlobStoring;
using Volo.Abp.Domain.Services;
using Volo.Abp.IO;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentManager : DomainService
{
private const string DefaultSaveToApplication = "abp-application";
private const string DefaultSaveToTempPath = "feedback-upload-tmp";
private readonly IBlobContainer<FeedbackContainer> _blobContainer;
private readonly IApplicationInfoAccessor _applicationInfoAccessor;
public FeedbackAttachmentManager(
IBlobContainer<FeedbackContainer> blobContainer,
IApplicationInfoAccessor applicationInfoAccessor)
{
_blobContainer = blobContainer;
_applicationInfoAccessor = applicationInfoAccessor;
}
/// <summary>
/// 将文件流写入临时存储
/// </summary>
/// <param name="stream">文件流</param>
/// <returns>返回临时存储的文件标识</returns>
public async Task<FeedbackAttachmentTempFile> SaveToTempAsync(Stream stream)
{
var blobSize = stream.Length;
var blobId = GuidGenerator.Create().ToString("N");
var timeStampPath = Clock.Now.ToString("yyyy-MM-dd");
var tempFilePath = Path.Combine(
Path.GetTempPath(),
_applicationInfoAccessor.ApplicationName ?? DefaultSaveToApplication,
DefaultSaveToTempPath,
timeStampPath);
var tempSavedFile = Path.Combine(tempFilePath, $"{blobId}.png");
DirectoryHelper.CreateIfNotExists(tempFilePath);
using (var fs = new FileStream(tempSavedFile, FileMode.Create, FileAccess.Write))
{
await stream.CopyToAsync(fs);
}
return new FeedbackAttachmentTempFile
{
Path = timeStampPath,
Size = blobSize,
Id = blobId,
};
}
/// <summary>
/// 从临时存储附件拷贝到blob存储
/// </summary>
/// <param name="feedback">用户反馈实体</param>
/// <param name="file">附件临时存储文件</param>
/// <returns>已保存的附件</returns>
public async Task<FeedbackAttachmentFile> CopyFromTempAsync(Feedback feedback, string filePtah, string fileId)
{
var fileName = $"{filePtah}/{fileId}.png";
var tempFilePath = Path.Combine(
Path.GetTempPath(),
_applicationInfoAccessor.ApplicationName ?? DefaultSaveToApplication,
DefaultSaveToTempPath);
var tempFromFile = Path.Combine(tempFilePath, fileName);
var blobFile = $"{fileId}.png";
var saveToBlobFile = $"{feedback.Id}/{blobFile}";
if (!File.Exists(tempFromFile))
{
throw new BusinessException(PlatformErrorCodes.FeedackAttachmentLoseEffectiveness)
.WithData("Name", fileId);
}
FeedbackAttachmentFile attachmentFile;
using (var fs = new FileStream(tempFromFile, FileMode.Open, FileAccess.Read))
{
await _blobContainer.SaveAsync(saveToBlobFile, fs, true);
attachmentFile = new FeedbackAttachmentFile(blobFile, fs.Length);
}
FileHelper.DeleteIfExists(tempFromFile);
return attachmentFile;
}
/// <summary>
/// 下载附件
/// </summary>
/// <param name="attachment">附件实体</param>
/// <returns>附件文件流</returns>
public async Task<Stream> DownloadAsync(FeedbackAttachment attachment)
{
var blobFile = $"{attachment.FeedbackId}/{attachment.Name}";
return await _blobContainer.GetAsync(blobFile);
}
/// <summary>
/// 删除附件
/// </summary>
/// <param name="attachment">附件实体</param>
/// <returns>附件文件流</returns>
public async Task DeleteAsync(FeedbackAttachment attachment)
{
var blobFile = $"{attachment.FeedbackId}/{attachment.Name}";
await _blobContainer.DeleteAsync(blobFile);
}
}

16
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackAttachmentNotFoundException.cs

@ -0,0 +1,16 @@
using Volo.Abp;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackAttachmentNotFoundException : BusinessException
{
public string Name { get; protected set; }
public FeedbackAttachmentNotFoundException(string name)
: base(
PlatformErrorCodes.FeedackAttachmentNotFound,
$"User feedback: Attachment named {name} not found!")
{
Name = name;
WithData("Name", name);
}
}

34
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackComment.cs

@ -0,0 +1,34 @@
using System;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Platform.Feedbacks;
/// <summary>
/// 评论
/// </summary>
public class FeedbackComment : AuditedEntity<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual string Capacity { get; protected set; }
public virtual string Content { get; set; }
public virtual Guid FeedbackId { get; protected set; }
protected FeedbackComment()
{
}
public FeedbackComment(
Guid id,
Guid feedbackId,
string capacity,
string content,
Guid? tenantId = null)
: base(id)
{
Capacity = Check.NotNullOrWhiteSpace(capacity, nameof(capacity), FeedbackCommentConsts.MaxCapacityLength);
Content = Check.NotNullOrWhiteSpace(content, nameof(content), FeedbackCommentConsts.MaxContentLength);
FeedbackId = feedbackId;
TenantId = tenantId;
}
}

8
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackContainer.cs

@ -0,0 +1,8 @@
using Volo.Abp.BlobStoring;
namespace LINGYUN.Platform.Feedbacks;
[BlobContainerName("feedbacks")]
public class FeedbackContainer
{
}

25
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/FeedbackStatusException.cs

@ -0,0 +1,25 @@
using LINGYUN.Platform.Localization;
using Microsoft.Extensions.Localization;
using Volo.Abp;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Localization;
namespace LINGYUN.Platform.Feedbacks;
public class FeedbackStatusException : BusinessException, ILocalizeErrorMessage
{
public FeedbackStatus Status { get; protected set; }
public FeedbackStatusException(string code, FeedbackStatus status)
: base(code, $"Unable to comment on issues in {status} status")
{
Status = status;
WithData("Status", status.ToString());
}
public string LocalizeMessage(LocalizationContext context)
{
var localizer = context.LocalizerFactory.Create<PlatformResource>();
return localizer[PlatformErrorCodes.UnableFeedbackCommentInStatus, localizer[$"FeedbackStatus:{Status}"]];
}
}

21
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/Feedbacks/IFeedbackRepository.cs

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
namespace LINGYUN.Platform.Feedbacks;
public interface IFeedbackRepository : IBasicRepository<Feedback, Guid>
{
Task<int> GetCountAsync(
ISpecification<Feedback> specification,
CancellationToken cancellationToken = default);
Task<List<Feedback>> GetListAsync(
ISpecification<Feedback> specification,
string sorting = $"{nameof(Feedback.CreationTime)} DESC",
int maxResultCount = 25,
int skipCount = 0,
CancellationToken cancellationToken = default);
}

128
aspnet-core/modules/platform/LINGYUN.Platform.Domain/LINGYUN/Platform/PlatformDomainModule.cs

@ -1,69 +1,69 @@
using LINGYUN.Platform.Datas; using LINGYUN.Platform.Datas;
using LINGYUN.Platform.Layouts; using LINGYUN.Platform.Layouts;
using LINGYUN.Platform.Menus; using LINGYUN.Platform.Menus;
using LINGYUN.Platform.ObjectExtending; using LINGYUN.Platform.ObjectExtending;
using LINGYUN.Platform.Packages; using LINGYUN.Platform.Packages;
using LINGYUN.Platform.Routes; using LINGYUN.Platform.Routes;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring;
using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus; using Volo.Abp.EventBus;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending.Modularity; using Volo.Abp.ObjectExtending.Modularity;
namespace LINGYUN.Platform; namespace LINGYUN.Platform;
[DependsOn( [DependsOn(
typeof(PlatformDomainSharedModule), typeof(PlatformDomainSharedModule),
typeof(AbpBlobStoringModule), typeof(AbpBlobStoringModule),
typeof(AbpEventBusModule))] typeof(AbpEventBusModule))]
public class PlatformDomainModule : AbpModule public class PlatformDomainModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
context.Services.AddAutoMapperObjectMapper<PlatformDomainModule>(); context.Services.AddAutoMapperObjectMapper<PlatformDomainModule>();
Configure<DataItemMappingOptions>(options => Configure<DataItemMappingOptions>(options =>
{ {
options.SetDefaultMapping(); options.SetDefaultMapping();
}); });
Configure<AbpAutoMapperOptions>(options => Configure<AbpAutoMapperOptions>(options =>
{ {
options.AddProfile<PlatformDomainMappingProfile>(validate: true); options.AddProfile<PlatformDomainMappingProfile>(validate: true);
}); });
Configure<AbpBlobStoringOptions>(options => Configure<AbpBlobStoringOptions>(options =>
{ {
options.Containers.Configure<PackageContainer>(containerConfiguration => options.Containers.Configure<PackageContainer>(containerConfiguration =>
{ {
containerConfiguration.IsMultiTenant = true; containerConfiguration.IsMultiTenant = true;
}); });
}); });
Configure<AbpDistributedEntityEventOptions>(options => Configure<AbpDistributedEntityEventOptions>(options =>
{ {
options.EtoMappings.Add<Layout, LayoutEto>(typeof(PlatformDomainModule)); options.EtoMappings.Add<Layout, LayoutEto>(typeof(PlatformDomainModule));
options.EtoMappings.Add<Menu, MenuEto>(typeof(PlatformDomainModule)); options.EtoMappings.Add<Menu, MenuEto>(typeof(PlatformDomainModule));
options.EtoMappings.Add<UserMenu, UserMenuEto>(typeof(PlatformDomainModule)); options.EtoMappings.Add<UserMenu, UserMenuEto>(typeof(PlatformDomainModule));
options.EtoMappings.Add<RoleMenu, RoleMenuEto>(typeof(PlatformDomainModule)); options.EtoMappings.Add<RoleMenu, RoleMenuEto>(typeof(PlatformDomainModule));
options.EtoMappings.Add<Package, PackageEto>(typeof(PlatformDomainModule)); options.EtoMappings.Add<Package, PackageEto>(typeof(PlatformDomainModule));
}); });
} }
public override void PostConfigureServices(ServiceConfigurationContext context) public override void PostConfigureServices(ServiceConfigurationContext context)
{ {
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity( ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
PlatformModuleExtensionConsts.ModuleName, PlatformModuleExtensionConsts.ModuleName,
PlatformModuleExtensionConsts.EntityNames.Route, PlatformModuleExtensionConsts.EntityNames.Route,
typeof(Route) typeof(Route)
); );
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity( ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
PlatformModuleExtensionConsts.ModuleName, PlatformModuleExtensionConsts.ModuleName,
PlatformModuleExtensionConsts.EntityNames.Package, PlatformModuleExtensionConsts.EntityNames.Package,
typeof(Package) typeof(Package)
); );
} }
} }

56
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformDbContextModelBuilderExtensions.cs

@ -1,5 +1,6 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using LINGYUN.Platform.Datas; using LINGYUN.Platform.Datas;
using LINGYUN.Platform.Feedbacks;
using LINGYUN.Platform.Layouts; using LINGYUN.Platform.Layouts;
using LINGYUN.Platform.Menus; using LINGYUN.Platform.Menus;
using LINGYUN.Platform.Packages; using LINGYUN.Platform.Packages;
@ -276,6 +277,61 @@ public static class PlatformDbContextModelBuilderExtensions
x.ConfigureByConvention(); x.ConfigureByConvention();
}); });
builder.Entity<Feedback>(x =>
{
x.ToTable(options.TablePrefix + "Feedbacks", options.Schema);
x.Property(p => p.Category)
.IsRequired()
.HasColumnName(nameof(Feedback.Category))
.HasMaxLength(FeedbackConsts.MaxCategoryLength);
x.Property(p => p.Content)
.IsRequired()
.HasColumnName(nameof(Feedback.Content))
.HasMaxLength(FeedbackConsts.MaxContentLength);
x.HasMany(p => p.Attachments)
.WithOne()
.HasForeignKey(fk => fk.FeedbackId)
.IsRequired();
x.HasMany(p => p.Comments)
.WithOne()
.HasForeignKey(fk => fk.FeedbackId)
.IsRequired();
x.ConfigureByConvention();
});
builder.Entity<FeedbackComment>(x =>
{
x.ToTable(options.TablePrefix + "FeedbackComments", options.Schema);
x.Property(p => p.Capacity)
.IsRequired()
.HasColumnName(nameof(FeedbackComment.Capacity))
.HasMaxLength(FeedbackCommentConsts.MaxCapacityLength);
x.Property(p => p.Content)
.IsRequired()
.HasColumnName(nameof(FeedbackComment.Content))
.HasMaxLength(FeedbackCommentConsts.MaxContentLength);
x.ConfigureByConvention();
});
builder.Entity<FeedbackAttachment>(x =>
{
x.ToTable(options.TablePrefix + "FeedbackAttachments", options.Schema);
x.Property(p => p.Name)
.IsRequired()
.HasColumnName(nameof(FeedbackAttachment.Name))
.HasMaxLength(FeedbackAttachmentConsts.MaxNameLength);
x.Property(p => p.Url)
.IsRequired()
.HasColumnName(nameof(FeedbackAttachment.Url))
.HasMaxLength(FeedbackAttachmentConsts.MaxUrlLength);
x.ConfigureByConvention();
});
} }
public static EntityTypeBuilder<TRoute> ConfigureRoute<TRoute>( public static EntityTypeBuilder<TRoute> ConfigureRoute<TRoute>(

3
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformEntityFrameworkCoreModule.cs

@ -1,4 +1,5 @@
using LINGYUN.Platform.Datas; using LINGYUN.Platform.Datas;
using LINGYUN.Platform.Feedbacks;
using LINGYUN.Platform.Layouts; using LINGYUN.Platform.Layouts;
using LINGYUN.Platform.Menus; using LINGYUN.Platform.Menus;
using LINGYUN.Platform.Packages; using LINGYUN.Platform.Packages;
@ -27,6 +28,8 @@ public class PlatformEntityFrameworkCoreModule : AbpModule
options.AddRepository<Package, EfCorePackageRepository>(); options.AddRepository<Package, EfCorePackageRepository>();
options.AddRepository<Enterprise, EfCoreEnterpriseRepository>(); options.AddRepository<Enterprise, EfCoreEnterpriseRepository>();
options.AddRepository<Feedback, EfCoreFeedbackRepository>();
options.AddDefaultRepositories(includeAllEntities: true); options.AddDefaultRepositories(includeAllEntities: true);
}); });
} }

51
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/Feedbacks/EfCoreFeedbackRepository.cs

@ -0,0 +1,51 @@
using LINGYUN.Platform.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Specifications;
namespace LINGYUN.Platform.Feedbacks;
public class EfCoreFeedbackRepository : EfCoreRepository<IPlatformDbContext, Feedback, Guid>, IFeedbackRepository
{
public EfCoreFeedbackRepository(
IDbContextProvider<IPlatformDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async virtual Task<int> GetCountAsync(
ISpecification<Feedback> specification,
CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync())
.Where(specification.ToExpression())
.CountAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<List<Feedback>> GetListAsync(
ISpecification<Feedback> specification,
string sorting = $"{nameof(Feedback.CreationTime)} DESC",
int maxResultCount = 25,
int skipCount = 0,
CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync())
.Where(specification.ToExpression())
.OrderBy(sorting.IsNullOrWhiteSpace() ? $"{nameof(Feedback.CreationTime)} DESC" : sorting)
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async override Task<IQueryable<Feedback>> WithDetailsAsync()
{
return (await base.WithDetailsAsync())
.Include(x => x.Comments)
.Include(x => x.Attachments);
}
}

43
aspnet-core/modules/platform/LINGYUN.Platform.HttpApi/LINGYUN/Platform/Feedbacks/FeedbackAttachmentController.cs

@ -0,0 +1,43 @@
using LINGYUN.Platform.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Content;
namespace LINGYUN.Platform.Feedbacks;
[Area(PlatformRemoteServiceConsts.ModuleName)]
[RemoteService(Name = PlatformRemoteServiceConsts.RemoteServiceName)]
[Route($"api/{PlatformRemoteServiceConsts.ModuleName}/feedbacks")]
[Authorize(PlatformPermissions.Feedback.Default)]
public class FeedbackAttachmentController : AbpControllerBase, IFeedbackAttachmentAppService
{
private readonly IFeedbackAttachmentAppService _service;
public FeedbackAttachmentController(IFeedbackAttachmentAppService service)
{
_service = service;
}
[HttpGet]
[Route("{FeedbackId}/attachments/{Name}")]
public virtual Task<IRemoteStreamContent> GetAsync(FeedbackAttachmentGetInput input)
{
return _service.GetAsync(input);
}
[HttpPost]
[Route("attachments/upload")]
public virtual Task<FeedbackAttachmentTempFileDto> UploadAsync([FromForm] FeedbackAttachmentUploadInput input)
{
return _service.UploadAsync(input);
}
[HttpDelete]
[Route("{FeedbackId}/attachments/{Name}")]
public virtual Task DeleteAsync(FeedbackAttachmentGetInput input)
{
return _service.DeleteAsync(input);
}
}

51
aspnet-core/modules/platform/LINGYUN.Platform.HttpApi/LINGYUN/Platform/Feedbacks/FeedbackController.cs

@ -0,0 +1,51 @@
using LINGYUN.Platform.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Platform.Feedbacks;
[Area(PlatformRemoteServiceConsts.ModuleName)]
[RemoteService(Name = PlatformRemoteServiceConsts.RemoteServiceName)]
[Route($"api/{PlatformRemoteServiceConsts.ModuleName}/feedbacks")]
[Authorize(PlatformPermissions.Feedback.Default)]
public class FeedbackController : AbpControllerBase, IFeedbackAppService
{
private readonly IFeedbackAppService _service;
public FeedbackController(IFeedbackAppService service)
{
_service = service;
}
[HttpPost]
[Authorize(PlatformPermissions.Feedback.Create)]
public virtual Task<FeedbackDto> CreateAsync(FeedbackCreateDto input)
{
return _service.CreateAsync(input);
}
[HttpDelete]
[Route("{id}")]
[Authorize(PlatformPermissions.Feedback.Delete)]
public virtual Task DeleteAsync(Guid id)
{
return _service.DeleteAsync(id);
}
[HttpGet]
[Route("{id}")]
public virtual Task<FeedbackDto> GetAsync(Guid id)
{
return _service.GetAsync(id);
}
[HttpGet]
public virtual Task<PagedResultDto<FeedbackDto>> GetListAsync(FeedbackGetListInput input)
{
return _service.GetListAsync(input);
}
}

27
aspnet-core/modules/platform/LINGYUN.Platform.HttpApi/LINGYUN/Platform/Feedbacks/MyFeedbackController.cs

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Platform.Feedbacks;
[Authorize]
[Area(PlatformRemoteServiceConsts.ModuleName)]
[RemoteService(Name = PlatformRemoteServiceConsts.RemoteServiceName)]
[Route($"api/{PlatformRemoteServiceConsts.ModuleName}/my-feedbacks")]
public class MyFeedbackController : AbpControllerBase, IMyFeedbackAppService
{
private readonly IMyFeedbackAppService _service;
public MyFeedbackController(IMyFeedbackAppService service)
{
_service = service;
}
[HttpGet]
public virtual Task<PagedResultDto<FeedbackDto>> GetMyFeedbacksAsync(FeedbackGetListInput input)
{
return _service.GetMyFeedbacksAsync(input);
}
}
Loading…
Cancel
Save