committed by
GitHub
57 changed files with 8873 additions and 195 deletions
@ -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); |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -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"); |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -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"); |
|||
} |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
namespace LINGYUN.Platform.Feedbacks; |
|||
public class FeedbackAttachmentTempFileCreateDto |
|||
{ |
|||
public string Path { get; set; } |
|||
public string Id { get; set; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace LINGYUN.Platform.Feedbacks; |
|||
public class FeedbackCommentUpdateDto : FeedbackCommentCreateOrUpdateDto, IHasConcurrencyStamp |
|||
{ |
|||
public string ConcurrencyStamp { get; set; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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)); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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 |
|||
{ |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
@ -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; |
|||
} |
|||
@ -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; } |
|||
} |
|||
@ -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; |
|||
} |
|||
@ -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; |
|||
} |
|||
@ -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 |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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() |
|||
{ |
|||
|
|||
} |
|||
|
|||
internal 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; |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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() |
|||
{ |
|||
|
|||
} |
|||
|
|||
internal 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; |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.BlobStoring; |
|||
|
|||
namespace LINGYUN.Platform.Feedbacks; |
|||
|
|||
[BlobContainerName("feedbacks")] |
|||
public class FeedbackContainer |
|||
{ |
|||
} |
|||
@ -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}"]]; |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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…
Reference in new issue