From 69db2379d8c3e19339dd78b80a485e8dc71ebd3a Mon Sep 17 00:00:00 2001 From: jxnkwlp Date: Tue, 2 Jan 2024 23:15:28 +0800 Subject: [PATCH] refactor file management --- .editorconfig | 183 ++ ...54223_Update_FileManagement_06.Designer.cs | 2496 +++++++++++++++++ ...20231228154223_Update_FileManagement_06.cs | 145 + .../SampleDbContextModelSnapshot.cs | 290 +- .../Properties/launchSettings.json | 3 +- .../SampleHttpApiHostModule.cs | 2 +- modules/common.props | 7 +- modules/file-management/common.props | 6 +- .../file-management.abpmdl.json | 79 + .../file-management.abpsln.json | 7 + modules/file-management/file-management.sln | 153 +- .../FileManagementAuthServerModule.cs | 2 +- .../Program.cs | 2 +- .../Program.cs | 2 +- .../Files/FileContainerBasicDto.cs | 11 + .../Files/FileContainerCanAccessResultDto.cs | 6 + .../Files/FileContainerCreateDto.cs | 2 +- .../Files/FileContainerDto.cs | 4 +- .../Files/FileContainerListRequestDto.cs | 2 +- .../Files/FileContainerListRequestDto1.cs | 6 + .../Files/FileContainerUpdateDto.cs | 10 +- .../Files/FileCreateByBytesDto.cs | 2 + .../Files/FileCreateByStreamDto.cs | 2 + .../Files/FileCreateDto.cs | 2 +- .../Files/FileMoveAdminRequestDto.cs | 10 + .../Files/FileMoveRequestDto.cs | 1 + .../Files/FileShareListRequestDto.cs | 9 + .../Files/FileShareResultDto.cs | 6 +- .../Files/IFileAdminAppService.cs | 31 + .../Files/IFileAppService.cs | 10 +- .../Files/IFileContainerAdminAppService.cs | 21 + .../Files/IFileContainerAppService.cs | 17 +- .../Files/IFileIntegrationAppService.cs | 21 - .../Files/IFileShareAppService.cs | 9 +- ...eManagementPermissionDefinitionProvider.cs | 15 +- .../Permissions/FileManagementPermissions.cs | 7 +- .../FileAdminAppService.cs | 268 ++ .../FileAppService.cs | 307 ++ .../FileContainerAdminAppService.cs | 132 + .../FileContainerAppService.cs | 45 + .../FileManagementAppService.cs | 21 +- ...eManagementApplicationAutoMapperProfile.cs | 3 +- .../FileShareAppService.cs | 221 ++ .../Files/FileAppService.cs | 360 --- .../Files/FileContainerAppService.cs | 181 -- .../Files/FileShareAppService.cs | 147 - .../FileManagementConsts.cs | 2 + .../Files/FileAccessMode.cs | 15 +- .../Localization/FileManagement/en.json | 4 +- .../Localization/FileManagement/zh-Hans.json | 4 +- .../FileShareTokenCleanupBackgroundWorker.cs | 5 +- .../DefaultFileAccessTokenProvider.cs | 70 + .../DefaultFileBlobContainerProvider.cs | 18 +- .../DefaultFileBlobNameGenerator.cs | 12 +- .../{Files => }/DefaultFileHashCalculator.cs | 4 +- .../DefaultFileRenameProvider.cs | 75 + .../DefaultFileUniqueIdGenerator.cs | 5 +- .../EventHandler/FileEventHander.cs | 17 +- .../FileAccessToken.cs | 42 + .../{Files => }/FileAccessTokenCacheItem.cs | 8 +- .../{Files => }/FileAccessTokenManager.cs | 4 +- .../{Files => }/FileAccessValidationResult.cs | 8 +- .../{Files => }/FileContainer.cs | 18 +- .../FileContainerAccess.cs | 20 + .../FileContainerAccessProvider.cs | 19 + .../FileContainerManager.cs | 80 + .../FileInfoCheckProvider.cs | 90 + .../{Files/File.cs => FileItem.cs} | 57 +- .../FileItemAccess.cs | 16 + .../FileItemAlreadyExistsException.cs | 18 + .../FileManagementDomainModule.cs | 7 +- .../FileManager.cs | 1067 +++++++ .../FileManagerExtensions.cs | 24 + .../FileMimeTypeProvider.cs | 15 + .../FileNameChangedEvent.cs | 31 + .../FileTags.cs | 15 + .../Files/DefaultFileAccessTokenProvider.cs | 105 - .../Files/DefaultFileRenameProvider.cs | 49 - .../Files/FileAccessToken.cs | 31 - .../Files/FileContainerManager.cs | 67 - .../FileHashDuplicateDetectionProvider.cs | 21 - .../Files/FileInfoCheckProvider.cs | 130 - .../Files/FileManager.cs | 453 --- .../Files/FileMimeTypeProvider.cs | 18 - .../FileNameDuplicateDetectionProvider.cs | 25 - .../Files/IFileAccessTokenProvider.cs | 12 - .../Files/IFileAccessTokenRepository.cs | 8 - .../Files/IFileBlobNameGenerator.cs | 10 - .../Files/IFileDuplicateDetectionProvider.cs | 9 - .../Files/IFileInfoCheckProvider.cs | 16 - .../Files/IFileManager.cs | 65 - .../Files/IFileRenameProvider.cs | 10 - .../Files/IFileRepository.cs | 24 - .../Files/IFileUniqueIdGenerator.cs | 10 - .../IFileAccessTokenProvider.cs | 9 + .../IFileAccessTokenRepository.cs | 14 + .../{Files => }/IFileBlobContainerProvider.cs | 2 +- .../IFileBlobNameGenerator.cs | 10 + .../IFileContainerAccessProvider.cs | 11 + .../IFileContainerManager.cs | 34 + .../{Files => }/IFileContainerRepository.cs | 4 +- .../IFileDuplicateDetectionProvider.cs | 11 + .../{Files => }/IFileHashCalculator.cs | 2 +- .../IFileInfoCheckProvider.cs | 19 + .../IFileManager.cs | 107 + .../{Files => }/IFileMimeTypeProvider.cs | 2 +- .../IFileRenameProvider.cs | 11 + .../IFileRepository.cs | 24 + .../IFileUniqueIdGenerator.cs | 10 + .../FileManagementDbContext.cs | 3 +- ...agementDbContextModelCreatingExtensions.cs | 63 +- .../IFileManagementDbContext.cs | 3 +- .../Repositories/FileAccessTokenRepository.cs | 43 +- .../Repositories/FileContainerRepository.cs | 13 +- .../Repositories/FileRepository.cs | 40 +- .../FileAdminController.cs | 107 + ...ler.cs => FileContainerAdminController.cs} | 25 +- .../FileContainerController.cs | 41 + .../{Files => }/FileController.cs | 23 +- .../{Files => }/FileShareController.cs | 36 +- .../Files/FileIntegrationController.cs | 51 - .../MongoDB/FileManagementMongoDbContext.cs | 3 +- .../FileManagementMongoDbContextExtensions.cs | 5 +- .../MongoDB/IFileManagementMongoDbContext.cs | 3 +- .../Repositories/FileAccessTokenRepository.cs | 47 +- .../Repositories/FileContainerRepository.cs | 19 +- .../MongoDB/Repositories/FileRepository.cs | 40 +- .../test/Directory.Build.props | 5 + .../FileAdminAppServiceTests.cs | 227 ++ .../FileManagementApplicationTestBase.cs | 11 + .../FileManagementApplicationTestModule.cs | 12 + .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 + ...leManagement.Application.Tests.abppkg.json | 3 + ...bp.FileManagement.Application.Tests.csproj | 17 + .../FileManagementDomainTestBase.cs | 9 + .../FileManagementDomainTestModule.cs | 16 + .../FileManagerTests.cs | 1574 +++++++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 + ...bp.FileManagement.Domain.Tests.abppkg.json | 3 + ...ind.Abp.FileManagement.Domain.Tests.csproj | 16 + ...leManagementEntityFrameworkCoreTestBase.cs | 9 + ...ManagementEntityFrameworkCoreTestModule.cs | 45 + .../Samples/SampleRepository_Tests.cs | 11 + .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 + ...ment.EntityFrameworkCore.Tests.abppkg.json | 3 + ...anagement.EntityFrameworkCore.Tests.csproj | 19 + .../ClientDemoService.cs | 153 + .../ConsoleTestAppHostedService.cs | 40 + .../FileManagementConsoleApiClientModule.cs | 15 + ....HttpApi.Client.ConsoleTestApp.abppkg.json | 1 + ...ement.HttpApi.Client.ConsoleTestApp.csproj | 33 + .../Program.cs | 22 + .../appsettings.json | 21 + .../appsettings.secrets.json | 2 + .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 + .../MongoDB/FileManagementMongoDbTestBase.cs | 9 + .../FileManagementMongoDbTestModule.cs | 21 + .../MongoDB/MongoDbFixture.cs | 34 + .../MongoDB/MongoTestCollection.cs | 9 + .../MongoDB/Samples/SampleRepository_Tests.cs | 13 + ...p.FileManagement.MongoDB.Tests.abppkg.json | 3 + ...nd.Abp.FileManagement.MongoDB.Tests.csproj | 21 + .../FileManagementDataSeedContributor.cs | 46 + .../FileManagementTestBase.cs | 59 + .../FileManagementTestBaseModule.cs | 41 + .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 + ...nd.Abp.FileManagement.TestBase.abppkg.json | 1 + ...ingwind.Abp.FileManagement.TestBase.csproj | 28 + .../Samples/SampleRepository_Tests.cs | 26 + .../Security/FakeCurrentPrincipalAccessor.cs | 27 + 175 files changed, 9485 insertions(+), 2219 deletions(-) create mode 100644 host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.Designer.cs create mode 100644 host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.cs create mode 100644 modules/file-management/file-management.abpmdl.json create mode 100644 modules/file-management/file-management.abpsln.json create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerBasicDto.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCanAccessResultDto.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto1.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveAdminRequestDto.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareListRequestDto.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAdminAppService.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAdminAppService.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileIntegrationAppService.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAdminAppService.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAppService.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAdminAppService.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAppService.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileShareAppService.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileAppService.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileContainerAppService.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileShareAppService.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileAccessTokenProvider.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/DefaultFileBlobContainerProvider.cs (67%) rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/DefaultFileBlobNameGenerator.cs (71%) rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/DefaultFileHashCalculator.cs (86%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileRenameProvider.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/DefaultFileUniqueIdGenerator.cs (52%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessToken.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/FileAccessTokenCacheItem.cs (63%) rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/FileAccessTokenManager.cs (84%) rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/FileAccessValidationResult.cs (60%) rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/FileContainer.cs (84%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccess.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccessProvider.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerManager.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileInfoCheckProvider.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files/File.cs => FileItem.cs} (51%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAccess.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAlreadyExistsException.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManager.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagerExtensions.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileMimeTypeProvider.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileNameChangedEvent.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileTags.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileAccessTokenProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileRenameProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessToken.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileContainerManager.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileHashDuplicateDetectionProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileInfoCheckProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileManager.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileMimeTypeProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileNameDuplicateDetectionProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenRepository.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileBlobNameGenerator.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileDuplicateDetectionProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileInfoCheckProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileManager.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRenameProvider.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRepository.cs delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileUniqueIdGenerator.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenProvider.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenRepository.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/IFileBlobContainerProvider.cs (83%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileBlobNameGenerator.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerAccessProvider.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerManager.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/IFileContainerRepository.cs (86%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileDuplicateDetectionProvider.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/IFileHashCalculator.cs (83%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileInfoCheckProvider.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileManager.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.Domain/{Files => }/IFileMimeTypeProvider.cs (74%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRenameProvider.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRepository.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileUniqueIdGenerator.cs create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileAdminController.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/{Files/FileContainerController.cs => FileContainerAdminController.cs} (66%) create mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileContainerController.cs rename modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/{Files => }/FileController.cs (81%) rename modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/{Files => }/FileShareController.cs (54%) delete mode 100644 modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileIntegrationController.cs create mode 100644 modules/file-management/test/Directory.Build.props create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileAdminAppServiceTests.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestBase.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestModule.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xml create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xsd create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.abppkg.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.csproj create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestBase.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestModule.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagerTests.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xml create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xsd create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.abppkg.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.csproj create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestBase.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestModule.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xml create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xsd create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.abppkg.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.csproj create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ClientDemoService.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ConsoleTestAppHostedService.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/FileManagementConsoleApiClientModule.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.abppkg.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.csproj create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Program.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.secrets.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xml create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xsd create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestBase.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestModule.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoDbFixture.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoTestCollection.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/Samples/SampleRepository_Tests.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.abppkg.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.csproj create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementDataSeedContributor.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBase.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBaseModule.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xml create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xsd create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.abppkg.json create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.csproj create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Samples/SampleRepository_Tests.cs create mode 100644 modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Security/FakeCurrentPrincipalAccessor.cs diff --git a/.editorconfig b/.editorconfig index 6673dc8..c988828 100644 --- a/.editorconfig +++ b/.editorconfig @@ -79,11 +79,194 @@ roslynator_refactorings.enabled = true # Enable/disable specific refactoring # roslynator_refactoring..enabled = true|false +dotnet_diagnostic.CA2016.severity = warning + # Enable/disable all compiler diagnostic fixes roslynator_compiler_diagnostic_fixes.enabled = true +csharp_indent_labels = one_less_than_current +csharp_space_around_binary_operators = before_and_after +csharp_using_directive_placement = outside_namespace:warning +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:warning +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion # Enable/disable specific compiler diagnostic fix # roslynator_compiler_diagnostic_fix..enabled = true|false [*.{cs,vb}] dotnet_diagnostic.IDE0058.severity = none +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_collection_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion + +[*.cs] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = warning +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.public_or_protected_field_should_be_pascal_case.severity = warning +dotnet_naming_rule.public_or_protected_field_should_be_pascal_case.symbols = public_or_protected_field +dotnet_naming_rule.public_or_protected_field_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.property_should_be_pascal_case.severity = warning +dotnet_naming_rule.property_should_be_pascal_case.symbols = property +dotnet_naming_rule.property_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.private_or_internal_field_should_be_begins_with__.severity = warning +dotnet_naming_rule.private_or_internal_field_should_be_begins_with__.symbols = private_or_internal_field +dotnet_naming_rule.private_or_internal_field_should_be_begins_with__.style = begins_with__ + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.public_or_protected_field.applicable_kinds = field +dotnet_naming_symbols.public_or_protected_field.applicable_accessibilities = public, protected +dotnet_naming_symbols.public_or_protected_field.required_modifiers = + +dotnet_naming_symbols.property.applicable_kinds = property +dotnet_naming_symbols.property.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.property.required_modifiers = + +dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_field.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with__.required_prefix = _ +dotnet_naming_style.begins_with__.required_suffix = +dotnet_naming_style.begins_with__.word_separator = +dotnet_naming_style.begins_with__.capitalization = camel_case +csharp_style_deconstructed_variable_declaration = true:suggestion + + +[*.vb] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case diff --git a/host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.Designer.cs b/host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.Designer.cs new file mode 100644 index 0000000..b847f94 --- /dev/null +++ b/host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.Designer.cs @@ -0,0 +1,2496 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Sample.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace Sample.Migrations +{ + [DbContext(typeof(SampleDbContext))] + [Migration("20231228154223_Update_FileManagement_06")] + partial class UpdateFileManagement06 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("ProductVersion", "7.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Passingwind.Abp.ApiKey.ApiKeyRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExpirationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("Secret") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("CreationTime") + .IsDescending(); + + b.HasIndex("Name"); + + b.HasIndex("Secret"); + + b.ToTable("PassingwindApiKeys", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileAccessToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DownloadCount") + .HasColumnType("bigint"); + + b.Property("ExpirationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FileId") + .HasColumnType("uniqueidentifier"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Length") + .HasColumnType("bigint"); + + b.Property("MimeType") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("FileId"); + + b.HasIndex("Token"); + + b.ToTable("FmFileAccessTokens", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessMode") + .HasColumnType("int"); + + b.Property("AllowAnyFileExtension") + .HasColumnType("bit"); + + b.Property("AllowedFileExtensions") + .HasColumnType("nvarchar(max)"); + + b.Property("AutoDeleteBlob") + .HasColumnType("bit"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FilesCount") + .HasColumnType("int"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MaximumEachFileSize") + .HasColumnType("bigint"); + + b.Property("MaximumFileQuantity") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("OverrideBehavior") + .HasColumnType("int"); + + b.Property("ProhibitedFileExtensions") + .HasColumnType("nvarchar(max)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("FmFileContainers", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileContainerAccess", b => + { + b.Property("FileContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Delete") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Read") + .HasColumnType("bit"); + + b.Property("Write") + .HasColumnType("bit"); + + b.HasKey("FileContainerId", "ProviderName", "ProviderKey"); + + b.ToTable("FmFileContainerAccesses", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Hash") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsDirectory") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Length") + .HasColumnType("bigint"); + + b.Property("MimeType") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UniqueId") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("CreationTime") + .IsDescending(); + + b.HasIndex("FileName"); + + b.HasIndex("Hash"); + + b.HasIndex("UniqueId"); + + b.ToTable("FmFiles", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileTags", b => + { + b.Property("FileId") + .HasColumnType("uniqueidentifier"); + + b.Property("Tags") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("FileId", "Tags"); + + b.ToTable("FmFileTags", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.Identity.IdentityUserTwoFactor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EmailToken") + .HasColumnType("bit"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("PhoneNumberToken") + .HasColumnType("bit"); + + b.Property("PreferredProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserTwoFactors", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("DisplayOrder") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDebugMode") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderType") + .HasColumnType("int"); + + b.Property("RequiredClaimTypes") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("CreationTime") + .IsDescending(); + + b.HasIndex("Name"); + + b.HasIndex("ProviderName"); + + b.ToTable("PassingwindIdentityClients", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClientClaimMap", b => + { + b.Property("IdentityClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Action") + .HasColumnType("int"); + + b.Property("RawValue") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ValueFromType") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("IdentityClientId", "ClaimType"); + + b.ToTable("PassingwindIdentityClientClaimMaps", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClientConfiguration", b => + { + b.Property("IdentityClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("IdentityClientId", "Name"); + + b.ToTable("PassingwindIdentityClientConfigurations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasColumnType("nvarchar(max)"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("int") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorTenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ImpersonatorTenantName"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorUserId"); + + b.Property("ImpersonatorUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ImpersonatorUserName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("TenantName"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("datetime2") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("tinyint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EntityChangeId") + .HasColumnType("uniqueidentifier"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsAbandoned") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("JobArgs") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("nvarchar(max)"); + + b.Property("JobName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LastTryTime") + .HasColumnType("datetime2"); + + b.Property("NextTryTime") + .HasColumnType("datetime2"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint") + .HasDefaultValue((byte)15); + + b.Property("TryCount") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)0); + + b.HasKey("Id"); + + b.HasIndex("IsAbandoned", "NextTryTime"); + + b.ToTable("AbpBackgroundJobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("bit"); + + b.Property("IsVisibleToClients") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatures", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + b.ToTable("AbpFeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("bit") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ClientSecret") + .HasColumnType("nvarchar(max)"); + + b.Property("ClientUri") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LogoUri") + .HasColumnType("nvarchar(max)"); + + b.Property("Permissions") + .HasColumnType("nvarchar(max)"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Requirements") + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("OpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Scopes") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Scopes.OpenIddictScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Descriptions") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Resources") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("OpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationId") + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorizationId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExpirationDate") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Payload") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedemptionDate") + .HasColumnType("datetime2"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[TenantId] IS NOT NULL"); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpTenants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileContainerAccess", b => + { + b.HasOne("Passingwind.Abp.FileManagement.Files.FileContainer", null) + .WithMany("Accesses") + .HasForeignKey("FileContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileTags", b => + { + b.HasOne("Passingwind.Abp.FileManagement.Files.FileItem", null) + .WithMany("Tags") + .HasForeignKey("FileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClientClaimMap", b => + { + b.HasOne("Passingwind.Abp.IdentityClient.IdentityClient", null) + .WithMany("ClaimMaps") + .HasForeignKey("IdentityClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClientConfiguration", b => + { + b.HasOne("Passingwind.Abp.IdentityClient.IdentityClient", null) + .WithMany("Configurations") + .HasForeignKey("IdentityClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + + b.HasOne("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", null) + .WithMany() + .HasForeignKey("AuthorizationId"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.HasOne("Volo.Abp.TenantManagement.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileContainer", b => + { + b.Navigation("Accesses"); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileItem", b => + { + b.Navigation("Tags"); + }); + + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClient", b => + { + b.Navigation("ClaimMaps"); + + b.Navigation("Configurations"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.cs b/host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.cs new file mode 100644 index 0000000..6d9ce90 --- /dev/null +++ b/host/src/Sample.EntityFrameworkCore/Migrations/20231228154223_Update_FileManagement_06.cs @@ -0,0 +1,145 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; + +#nullable disable + +namespace Sample.Migrations; + +/// +public partial class UpdateFileManagement06 : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "EntityVersion", + table: "FmFiles", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "EntityVersion", + table: "FmFileContainers", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "ContainerId", + table: "FmFileAccessTokens", + type: "uniqueidentifier", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + migrationBuilder.AddColumn( + name: "FileName", + table: "FmFileAccessTokens", + type: "nvarchar(256)", + maxLength: 256, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "Length", + table: "FmFileAccessTokens", + type: "bigint", + nullable: false, + defaultValue: 0L); + + migrationBuilder.AddColumn( + name: "MimeType", + table: "FmFileAccessTokens", + type: "nvarchar(128)", + maxLength: 128, + nullable: true); + + migrationBuilder.AddColumn( + name: "TenantId", + table: "FmFileAccessTokens", + type: "uniqueidentifier", + nullable: true); + + migrationBuilder.CreateTable( + name: "FmFileContainerAccesses", + columns: table => new + { + FileContainerId = table.Column(type: "uniqueidentifier", nullable: false), + ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + Read = table.Column(type: "bit", nullable: false), + Write = table.Column(type: "bit", nullable: false), + Delete = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_FmFileContainerAccesses", x => new { x.FileContainerId, x.ProviderName, x.ProviderKey }); + table.ForeignKey( + name: "FK_FmFileContainerAccesses_FmFileContainers_FileContainerId", + column: x => x.FileContainerId, + principalTable: "FmFileContainers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "FmFileTags", + columns: table => new + { + FileId = table.Column(type: "uniqueidentifier", nullable: false), + Tags = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FmFileTags", x => new { x.FileId, x.Tags }); + table.ForeignKey( + name: "FK_FmFileTags_FmFiles_FileId", + column: x => x.FileId, + principalTable: "FmFiles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "FmFileContainerAccesses"); + + migrationBuilder.DropTable( + name: "FmFileTags"); + + migrationBuilder.DropColumn( + name: "EntityVersion", + table: "FmFiles"); + + migrationBuilder.DropColumn( + name: "EntityVersion", + table: "FmFileContainers"); + + migrationBuilder.DropColumn( + name: "ContainerId", + table: "FmFileAccessTokens"); + + migrationBuilder.DropColumn( + name: "FileName", + table: "FmFileAccessTokens"); + + migrationBuilder.DropColumn( + name: "Length", + table: "FmFileAccessTokens"); + + migrationBuilder.DropColumn( + name: "MimeType", + table: "FmFileAccessTokens"); + + migrationBuilder.DropColumn( + name: "TenantId", + table: "FmFileAccessTokens"); + } +} diff --git a/host/src/Sample.EntityFrameworkCore/Migrations/SampleDbContextModelSnapshot.cs b/host/src/Sample.EntityFrameworkCore/Migrations/SampleDbContextModelSnapshot.cs index cbad3f6..e306b92 100644 --- a/host/src/Sample.EntityFrameworkCore/Migrations/SampleDbContextModelSnapshot.cs +++ b/host/src/Sample.EntityFrameworkCore/Migrations/SampleDbContextModelSnapshot.cs @@ -88,17 +88,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("PassingwindApiKeys", (string)null); }); - modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.File", b => + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileAccessToken", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); - b.Property("BlobName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("nvarchar(256)"); - b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasMaxLength(40) @@ -116,44 +111,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uniqueidentifier") .HasColumnName("CreatorId"); - b.Property("DeleterId") - .HasColumnType("uniqueidentifier") - .HasColumnName("DeleterId"); + b.Property("DownloadCount") + .HasColumnType("bigint"); - b.Property("DeletionTime") - .HasColumnType("datetime2") - .HasColumnName("DeletionTime"); + b.Property("ExpirationTime") + .HasColumnType("datetime2"); b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); + b.Property("FileId") + .HasColumnType("uniqueidentifier"); + b.Property("FileName") .IsRequired() .HasMaxLength(256) .HasColumnType("nvarchar(256)"); - b.Property("Hash") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("IsDirectory") - .HasColumnType("bit"); - - b.Property("LastModificationTime") - .HasColumnType("datetime2") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uniqueidentifier") - .HasColumnName("LastModifierId"); - b.Property("Length") .HasColumnType("bigint"); @@ -161,67 +136,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(128) .HasColumnType("nvarchar(128)"); - b.Property("ParentId") - .HasColumnType("uniqueidentifier"); - b.Property("TenantId") .HasColumnType("uniqueidentifier") .HasColumnName("TenantId"); - b.Property("UniqueId") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("nvarchar(32)"); - - b.HasKey("Id"); - - b.HasIndex("ContainerId"); - - b.HasIndex("CreationTime") - .IsDescending(); - - b.HasIndex("FileName"); - - b.HasIndex("Hash"); - - b.HasIndex("UniqueId"); - - b.ToTable("FmFiles", (string)null); - }); - - modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileAccessToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasMaxLength(40) - .HasColumnType("nvarchar(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("CreatorId") - .HasColumnType("uniqueidentifier") - .HasColumnName("CreatorId"); - - b.Property("DownloadCount") - .HasColumnType("bigint"); - - b.Property("ExpirationTime") - .HasColumnType("datetime2"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("FileId") - .HasColumnType("uniqueidentifier"); - b.Property("Token") .IsRequired() .HasMaxLength(256) @@ -280,6 +198,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(256) .HasColumnType("nvarchar(256)"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -329,6 +250,167 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("FmFileContainers", (string)null); }); + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileContainerAccess", b => + { + b.Property("FileContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Delete") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Read") + .HasColumnType("bit"); + + b.Property("Write") + .HasColumnType("bit"); + + b.HasKey("FileContainerId", "ProviderName", "ProviderKey"); + + b.ToTable("FmFileContainerAccesses", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Hash") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsDirectory") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Length") + .HasColumnType("bigint"); + + b.Property("MimeType") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UniqueId") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("CreationTime") + .IsDescending(); + + b.HasIndex("FileName"); + + b.HasIndex("Hash"); + + b.HasIndex("UniqueId"); + + b.ToTable("FmFiles", (string)null); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileTags", b => + { + b.Property("FileId") + .HasColumnType("uniqueidentifier"); + + b.Property("Tags") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("FileId", "Tags"); + + b.ToTable("FmFileTags", (string)null); + }); + modelBuilder.Entity("Passingwind.Abp.Identity.IdentityUserTwoFactor", b => { b.Property("Id") @@ -2171,6 +2253,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AbpTenantConnectionStrings", (string)null); }); + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileContainerAccess", b => + { + b.HasOne("Passingwind.Abp.FileManagement.Files.FileContainer", null) + .WithMany("Accesses") + .HasForeignKey("FileContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileTags", b => + { + b.HasOne("Passingwind.Abp.FileManagement.Files.FileItem", null) + .WithMany("Tags") + .HasForeignKey("FileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClientClaimMap", b => { b.HasOne("Passingwind.Abp.IdentityClient.IdentityClient", null) @@ -2331,6 +2431,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileContainer", b => + { + b.Navigation("Accesses"); + }); + + modelBuilder.Entity("Passingwind.Abp.FileManagement.Files.FileItem", b => + { + b.Navigation("Tags"); + }); + modelBuilder.Entity("Passingwind.Abp.IdentityClient.IdentityClient", b => { b.Navigation("ClaimMaps"); diff --git a/host/src/Sample.HttpApi.Host/Properties/launchSettings.json b/host/src/Sample.HttpApi.Host/Properties/launchSettings.json index c8e79b9..fea7fc9 100644 --- a/host/src/Sample.HttpApi.Host/Properties/launchSettings.json +++ b/host/src/Sample.HttpApi.Host/Properties/launchSettings.json @@ -3,7 +3,8 @@ "Sample.HttpApi.Host": { "commandName": "Project", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_WATCH_SUPPRESS_BROWSER_REFRESH": "true" }, "applicationUrl": "https://localhost:53557;http://localhost:53558" } diff --git a/host/src/Sample.HttpApi.Host/SampleHttpApiHostModule.cs b/host/src/Sample.HttpApi.Host/SampleHttpApiHostModule.cs index 14c4fc6..a16b8c7 100644 --- a/host/src/Sample.HttpApi.Host/SampleHttpApiHostModule.cs +++ b/host/src/Sample.HttpApi.Host/SampleHttpApiHostModule.cs @@ -91,7 +91,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) Configure(options => { options.DefaultOverrideBehavior = Passingwind.Abp.FileManagement.Files.FileOverrideBehavior.Rename; - options.DefaultContainerAccessMode = Passingwind.Abp.FileManagement.Files.FileAccessMode.Readonly; + options.DefaultContainerAccessMode = Passingwind.Abp.FileManagement.Files.FileAccessMode.AnonymousReadonly; }); context.Services.AddHangfire(config => diff --git a/modules/common.props b/modules/common.props index d814fb4..e56c44e 100644 --- a/modules/common.props +++ b/modules/common.props @@ -1,10 +1,15 @@  latest + enable $(Version) $(Version) $(NoWarn);CS1591 - + true + true + + + true Passingwind Passingwind diff --git a/modules/file-management/common.props b/modules/file-management/common.props index b110782..a33ff73 100644 --- a/modules/file-management/common.props +++ b/modules/file-management/common.props @@ -1,12 +1,12 @@ - + Passingwind.Abp.FileManagement an abp module that provider file and file container management. abp-module - 0.2.0 - 0.2.2 + 1.0.0 + 1.0.0-bate.1 diff --git a/modules/file-management/file-management.abpmdl.json b/modules/file-management/file-management.abpmdl.json new file mode 100644 index 0000000..a056b00 --- /dev/null +++ b/modules/file-management/file-management.abpmdl.json @@ -0,0 +1,79 @@ +{ + "folders": { + "items": { + "src": {}, + "test": {}, + "host": {} + } + }, + "packages": { + "Passingwind.Abp.FileManagement.Domain.Shared": { + "path": "src/Passingwind.Abp.FileManagement.Domain.Shared/Passingwind.Abp.FileManagement.Domain.Shared.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.Domain": { + "path": "src/Passingwind.Abp.FileManagement.Domain/Passingwind.Abp.FileManagement.Domain.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.Application.Contracts": { + "path": "src/Passingwind.Abp.FileManagement.Application.Contracts/Passingwind.Abp.FileManagement.Application.Contracts.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.Application": { + "path": "src/Passingwind.Abp.FileManagement.Application/Passingwind.Abp.FileManagement.Application.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.EntityFrameworkCore": { + "path": "src/Passingwind.Abp.FileManagement.EntityFrameworkCore/Passingwind.Abp.FileManagement.EntityFrameworkCore.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.MongoDB": { + "path": "src/Passingwind.Abp.FileManagement.MongoDB/Passingwind.Abp.FileManagement.MongoDB.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.HttpApi": { + "path": "src/Passingwind.Abp.FileManagement.HttpApi/Passingwind.Abp.FileManagement.HttpApi.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.HttpApi.Client": { + "path": "src/Passingwind.Abp.FileManagement.HttpApi.Client/Passingwind.Abp.FileManagement.HttpApi.Client.abppkg.json", + "folder": "src" + }, + "Passingwind.Abp.FileManagement.TestBase": { + "path": "test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.abppkg.json", + "folder": "test" + }, + "Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests": { + "path": "test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.abppkg.json", + "folder": "test" + }, + "Passingwind.Abp.FileManagement.MongoDB.Tests": { + "path": "test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.abppkg.json", + "folder": "test" + }, + "Passingwind.Abp.FileManagement.Domain.Tests": { + "path": "test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.abppkg.json", + "folder": "test" + }, + "Passingwind.Abp.FileManagement.Application.Tests": { + "path": "test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.abppkg.json", + "folder": "test" + }, + "Passingwind.Abp.FileManagement.HttpApi.Host": { + "path": "host/Passingwind.Abp.FileManagement.HttpApi.Host/Passingwind.Abp.FileManagement.HttpApi.Host.abppkg.json", + "folder": "host" + }, + "Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp": { + "path": "test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.abppkg.json", + "folder": "test" + }, + "Passingwind.Abp.FileManagement.AuthServer": { + "path": "host/Passingwind.Abp.FileManagement.AuthServer/Passingwind.Abp.FileManagement.AuthServer.abppkg.json", + "folder": "host" + }, + "Passingwind.Abp.FileManagement.Host.Shared": { + "path": "host/Passingwind.Abp.FileManagement.Host.Shared/Passingwind.Abp.FileManagement.Host.Shared.abppkg.json", + "folder": "host" + } + } +} \ No newline at end of file diff --git a/modules/file-management/file-management.abpsln.json b/modules/file-management/file-management.abpsln.json new file mode 100644 index 0000000..58205ca --- /dev/null +++ b/modules/file-management/file-management.abpsln.json @@ -0,0 +1,7 @@ +{ + "modules": { + "Passingwind.Abp.FileManagement": { + "path": "Passingwind.Abp.FileManagement.abpmdl.json" + } + } +} \ No newline at end of file diff --git a/modules/file-management/file-management.sln b/modules/file-management/file-management.sln index 12d3d60..0d53160 100644 --- a/modules/file-management/file-management.sln +++ b/modules/file-management/file-management.sln @@ -1,25 +1,41 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.6.33723.286 +VisualStudioVersion = 17.8.34330.188 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Domain.Shared", "src\Passingwind.Abp.FileManagement.Domain.Shared\Passingwind.Abp.FileManagement.Domain.Shared.csproj", "{D64C1577-4929-4B60-939E-96DE1534891A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Domain.Shared", "src\Passingwind.Abp.FileManagement.Domain.Shared\Passingwind.Abp.FileManagement.Domain.Shared.csproj", "{31A9127C-C471-4F73-8FCA-BDD0519986C8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Domain", "src\Passingwind.Abp.FileManagement.Domain\Passingwind.Abp.FileManagement.Domain.csproj", "{F2840BC7-0188-4606-9126-DADD0F5ABF7A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Domain", "src\Passingwind.Abp.FileManagement.Domain\Passingwind.Abp.FileManagement.Domain.csproj", "{0D00F944-53B6-42E9-A62D-53F5522C5E5D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Application.Contracts", "src\Passingwind.Abp.FileManagement.Application.Contracts\Passingwind.Abp.FileManagement.Application.Contracts.csproj", "{BD65D04F-08D5-40C1-8C24-77CA0BACB877}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.EntityFrameworkCore", "src\Passingwind.Abp.FileManagement.EntityFrameworkCore\Passingwind.Abp.FileManagement.EntityFrameworkCore.csproj", "{3ECA083D-5079-41E8-9E69-F19A825044D5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Application", "src\Passingwind.Abp.FileManagement.Application\Passingwind.Abp.FileManagement.Application.csproj", "{78040F9E-3501-4A40-82DF-00A597710F35}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.MongoDB", "src\Passingwind.Abp.FileManagement.MongoDB\Passingwind.Abp.FileManagement.MongoDB.csproj", "{1BA20FF7-DDC0-4DE1-AD67-A221CE7EFC3A}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{649A3FFA-182F-4E56-9717-E6A9A2BEC545}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Application.Contracts", "src\Passingwind.Abp.FileManagement.Application.Contracts\Passingwind.Abp.FileManagement.Application.Contracts.csproj", "{61845F32-051F-42CC-A8BD-826E5CB5575F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Application", "src\Passingwind.Abp.FileManagement.Application\Passingwind.Abp.FileManagement.Application.csproj", "{9DAFDB79-0808-40DC-8FFA-CB98E91D1B6D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.EntityFrameworkCore", "src\Passingwind.Abp.FileManagement.EntityFrameworkCore\Passingwind.Abp.FileManagement.EntityFrameworkCore.csproj", "{0CE86223-D31D-4315-A1F5-87BA3EE1B844}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.HttpApi", "src\Passingwind.Abp.FileManagement.HttpApi\Passingwind.Abp.FileManagement.HttpApi.csproj", "{026DE9E8-AB47-40F3-AF3E-4FBD88E65C7A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.MongoDB", "src\Passingwind.Abp.FileManagement.MongoDB\Passingwind.Abp.FileManagement.MongoDB.csproj", "{F1C58097-4C08-4D88-8976-6B3389391481}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.HttpApi.Client", "src\Passingwind.Abp.FileManagement.HttpApi.Client\Passingwind.Abp.FileManagement.HttpApi.Client.csproj", "{1402A0AA-531B-4EF3-ABEB-8CB460FCA961}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.HttpApi", "src\Passingwind.Abp.FileManagement.HttpApi\Passingwind.Abp.FileManagement.HttpApi.csproj", "{077AA5F8-8B61-420C-A6B5-0150A66FDB34}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.HttpApi.Client", "src\Passingwind.Abp.FileManagement.HttpApi.Client\Passingwind.Abp.FileManagement.HttpApi.Client.csproj", "{36E2735F-CEAB-44C8-A6D1-2CDAFF399751}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.TestBase", "test\Passingwind.Abp.FileManagement.TestBase\Passingwind.Abp.FileManagement.TestBase.csproj", "{C5BB573D-3030-4BCB-88B7-F6A85C32766C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests", "test\Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests\Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.csproj", "{527F645C-C1FC-406E-8479-81386C8ECF13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.MongoDB.Tests", "test\Passingwind.Abp.FileManagement.MongoDB.Tests\Passingwind.Abp.FileManagement.MongoDB.Tests.csproj", "{D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Domain.Tests", "test\Passingwind.Abp.FileManagement.Domain.Tests\Passingwind.Abp.FileManagement.Domain.Tests.csproj", "{E60895E5-79C4-447D-88B7-85CB5BA336A4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Application.Tests", "test\Passingwind.Abp.FileManagement.Application.Tests\Passingwind.Abp.FileManagement.Application.Tests.csproj", "{90CB5DC4-C040-45C7-8900-9688B26405BC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp", "test\Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp\Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.csproj", "{1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Passingwind.Abp.FileManagement.Installer", "src\Passingwind.Abp.FileManagement.Installer\Passingwind.Abp.FileManagement.Installer.csproj", "{BE39FD00-745B-4049-8161-FC129817CBE4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,53 +43,88 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {31A9127C-C471-4F73-8FCA-BDD0519986C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {31A9127C-C471-4F73-8FCA-BDD0519986C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {31A9127C-C471-4F73-8FCA-BDD0519986C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {31A9127C-C471-4F73-8FCA-BDD0519986C8}.Release|Any CPU.Build.0 = Release|Any CPU - {0D00F944-53B6-42E9-A62D-53F5522C5E5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0D00F944-53B6-42E9-A62D-53F5522C5E5D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0D00F944-53B6-42E9-A62D-53F5522C5E5D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0D00F944-53B6-42E9-A62D-53F5522C5E5D}.Release|Any CPU.Build.0 = Release|Any CPU - {3ECA083D-5079-41E8-9E69-F19A825044D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3ECA083D-5079-41E8-9E69-F19A825044D5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3ECA083D-5079-41E8-9E69-F19A825044D5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3ECA083D-5079-41E8-9E69-F19A825044D5}.Release|Any CPU.Build.0 = Release|Any CPU - {1BA20FF7-DDC0-4DE1-AD67-A221CE7EFC3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1BA20FF7-DDC0-4DE1-AD67-A221CE7EFC3A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1BA20FF7-DDC0-4DE1-AD67-A221CE7EFC3A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1BA20FF7-DDC0-4DE1-AD67-A221CE7EFC3A}.Release|Any CPU.Build.0 = Release|Any CPU - {61845F32-051F-42CC-A8BD-826E5CB5575F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {61845F32-051F-42CC-A8BD-826E5CB5575F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {61845F32-051F-42CC-A8BD-826E5CB5575F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {61845F32-051F-42CC-A8BD-826E5CB5575F}.Release|Any CPU.Build.0 = Release|Any CPU - {9DAFDB79-0808-40DC-8FFA-CB98E91D1B6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9DAFDB79-0808-40DC-8FFA-CB98E91D1B6D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9DAFDB79-0808-40DC-8FFA-CB98E91D1B6D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9DAFDB79-0808-40DC-8FFA-CB98E91D1B6D}.Release|Any CPU.Build.0 = Release|Any CPU - {026DE9E8-AB47-40F3-AF3E-4FBD88E65C7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {026DE9E8-AB47-40F3-AF3E-4FBD88E65C7A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {026DE9E8-AB47-40F3-AF3E-4FBD88E65C7A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {026DE9E8-AB47-40F3-AF3E-4FBD88E65C7A}.Release|Any CPU.Build.0 = Release|Any CPU - {1402A0AA-531B-4EF3-ABEB-8CB460FCA961}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1402A0AA-531B-4EF3-ABEB-8CB460FCA961}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1402A0AA-531B-4EF3-ABEB-8CB460FCA961}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1402A0AA-531B-4EF3-ABEB-8CB460FCA961}.Release|Any CPU.Build.0 = Release|Any CPU + {D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.Build.0 = Release|Any CPU + {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.Build.0 = Release|Any CPU + {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Release|Any CPU.Build.0 = Release|Any CPU + {78040F9E-3501-4A40-82DF-00A597710F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78040F9E-3501-4A40-82DF-00A597710F35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78040F9E-3501-4A40-82DF-00A597710F35}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78040F9E-3501-4A40-82DF-00A597710F35}.Release|Any CPU.Build.0 = Release|Any CPU + {0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CE86223-D31D-4315-A1F5-87BA3EE1B844}.Release|Any CPU.Build.0 = Release|Any CPU + {F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.Build.0 = Release|Any CPU + {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Release|Any CPU.Build.0 = Release|Any CPU + {36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36E2735F-CEAB-44C8-A6D1-2CDAFF399751}.Release|Any CPU.Build.0 = Release|Any CPU + {C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5BB573D-3030-4BCB-88B7-F6A85C32766C}.Release|Any CPU.Build.0 = Release|Any CPU + {527F645C-C1FC-406E-8479-81386C8ECF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {527F645C-C1FC-406E-8479-81386C8ECF13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {527F645C-C1FC-406E-8479-81386C8ECF13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {527F645C-C1FC-406E-8479-81386C8ECF13}.Release|Any CPU.Build.0 = Release|Any CPU + {D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6}.Release|Any CPU.Build.0 = Release|Any CPU + {E60895E5-79C4-447D-88B7-85CB5BA336A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E60895E5-79C4-447D-88B7-85CB5BA336A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E60895E5-79C4-447D-88B7-85CB5BA336A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E60895E5-79C4-447D-88B7-85CB5BA336A4}.Release|Any CPU.Build.0 = Release|Any CPU + {90CB5DC4-C040-45C7-8900-9688B26405BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90CB5DC4-C040-45C7-8900-9688B26405BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90CB5DC4-C040-45C7-8900-9688B26405BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90CB5DC4-C040-45C7-8900-9688B26405BC}.Release|Any CPU.Build.0 = Release|Any CPU + {1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8}.Release|Any CPU.Build.0 = Release|Any CPU + {BE39FD00-745B-4049-8161-FC129817CBE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE39FD00-745B-4049-8161-FC129817CBE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE39FD00-745B-4049-8161-FC129817CBE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE39FD00-745B-4049-8161-FC129817CBE4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {31A9127C-C471-4F73-8FCA-BDD0519986C8} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} - {0D00F944-53B6-42E9-A62D-53F5522C5E5D} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} - {3ECA083D-5079-41E8-9E69-F19A825044D5} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} - {1BA20FF7-DDC0-4DE1-AD67-A221CE7EFC3A} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} - {61845F32-051F-42CC-A8BD-826E5CB5575F} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} - {9DAFDB79-0808-40DC-8FFA-CB98E91D1B6D} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} - {026DE9E8-AB47-40F3-AF3E-4FBD88E65C7A} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} - {1402A0AA-531B-4EF3-ABEB-8CB460FCA961} = {4D237CB9-A9B0-468C-9EA1-C57AAA1E72C7} + {D64C1577-4929-4B60-939E-96DE1534891A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {F2840BC7-0188-4606-9126-DADD0F5ABF7A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {BD65D04F-08D5-40C1-8C24-77CA0BACB877} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {78040F9E-3501-4A40-82DF-00A597710F35} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {0CE86223-D31D-4315-A1F5-87BA3EE1B844} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {F1C58097-4C08-4D88-8976-6B3389391481} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {077AA5F8-8B61-420C-A6B5-0150A66FDB34} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {36E2735F-CEAB-44C8-A6D1-2CDAFF399751} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} + {C5BB573D-3030-4BCB-88B7-F6A85C32766C} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} + {527F645C-C1FC-406E-8479-81386C8ECF13} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} + {D0AD9179-125C-40B2-A8EE-CD4C1EE24BB6} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} + {E60895E5-79C4-447D-88B7-85CB5BA336A4} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} + {90CB5DC4-C040-45C7-8900-9688B26405BC} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} + {1EDCD6D4-DF3A-4E3B-ABB6-C0D0B373EAB8} = {CCD2960C-23CC-4AB4-B84D-60C7AAA52F4D} + {BE39FD00-745B-4049-8161-FC129817CBE4} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F} + SolutionGuid = {4324B3B4-B60B-4E3C-91D8-59576B4E26DD} EndGlobalSection EndGlobal diff --git a/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/FileManagementAuthServerModule.cs b/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/FileManagementAuthServerModule.cs index 22599ca..31547da 100644 --- a/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/FileManagementAuthServerModule.cs +++ b/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/FileManagementAuthServerModule.cs @@ -193,7 +193,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) #endif } - public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + public virtual async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); diff --git a/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/Program.cs b/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/Program.cs index c1676f6..b4f6561 100644 --- a/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/Program.cs +++ b/modules/file-management/host/Passingwind.Abp.FileManagement.AuthServer/Program.cs @@ -10,7 +10,7 @@ namespace Passingwind.Abp.FileManagement; public class Program { - public async static Task Main(string[] args) + public virtual async static Task Main(string[] args) { Log.Logger = new LoggerConfiguration() #if DEBUG diff --git a/modules/file-management/host/Passingwind.Abp.FileManagement.HttpApi.Host/Program.cs b/modules/file-management/host/Passingwind.Abp.FileManagement.HttpApi.Host/Program.cs index f0a5a39..72a8d2a 100644 --- a/modules/file-management/host/Passingwind.Abp.FileManagement.HttpApi.Host/Program.cs +++ b/modules/file-management/host/Passingwind.Abp.FileManagement.HttpApi.Host/Program.cs @@ -10,7 +10,7 @@ namespace Passingwind.Abp.FileManagement; public class Program { - public async static Task Main(string[] args) + public virtual async static Task Main(string[] args) { Log.Logger = new LoggerConfiguration() #if DEBUG diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerBasicDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerBasicDto.cs new file mode 100644 index 0000000..5e92352 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerBasicDto.cs @@ -0,0 +1,11 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Passingwind.Abp.FileManagement.Files; + +public class FileContainerBasicDto : ExtensibleAuditedEntityDto +{ + public virtual string Name { get; set; } = null!; + public virtual string? Description { get; set; } + public virtual int FilesCount { get; set; } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCanAccessResultDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCanAccessResultDto.cs new file mode 100644 index 0000000..2bbd4e7 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCanAccessResultDto.cs @@ -0,0 +1,6 @@ +namespace Passingwind.Abp.FileManagement.Files; + +public class FileContainerCanAccessResultDto +{ + public bool Result { get; set; } +} \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCreateDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCreateDto.cs index 808983d..e8224ff 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCreateDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerCreateDto.cs @@ -2,7 +2,7 @@ namespace Passingwind.Abp.FileManagement.Files; -public class FileContainerCreateDto : FileContainerCreateOrUpdateBasicDto +public class FileContainerAdminCreateDto : FileContainerCreateOrUpdateBasicDto { [RegularExpression(@"^[\\u4e00-\\u9fa5A-Za-z0-9\\-\\_]*$")] [MaxLength(32)] diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerDto.cs index c0b8d93..45e9711 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerDto.cs @@ -1,9 +1,10 @@ using System; using Volo.Abp.Application.Dtos; +using Volo.Abp.Domain.Entities; namespace Passingwind.Abp.FileManagement.Files; -public class FileContainerDto : ExtensibleAuditedEntityDto +public class FileContainerDto : ExtensibleAuditedEntityDto, IHasConcurrencyStamp { public virtual string Name { get; set; } = null!; public virtual string? Description { get; set; } @@ -18,4 +19,5 @@ public class FileContainerDto : ExtensibleAuditedEntityDto public virtual string? ProhibitedFileExtensions { get; set; } public virtual int FilesCount { get; set; } public virtual bool AutoDeleteBlob { get; set; } + public virtual string? ConcurrencyStamp { get; set; } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto.cs index bfc88ab..e9dace5 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto.cs @@ -2,7 +2,7 @@ namespace Passingwind.Abp.FileManagement.Files; -public class FileContainerListRequestDto : PagedResultRequestDto +public class FileContainerAdminListRequestDto : PagedResultRequestDto { public string? Filter { get; set; } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto1.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto1.cs new file mode 100644 index 0000000..ce8b283 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerListRequestDto1.cs @@ -0,0 +1,6 @@ +namespace Passingwind.Abp.FileManagement.Files; + +public class FileContainerListRequestDto +{ + public bool OnlyGranted { get; set; } +} \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerUpdateDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerUpdateDto.cs index 4f3faf9..26287a8 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerUpdateDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileContainerUpdateDto.cs @@ -1,4 +1,8 @@ -namespace Passingwind.Abp.FileManagement.Files; +using Volo.Abp.Domain.Entities; -public class FileContainerUpdateDto : FileContainerCreateOrUpdateBasicDto -{ } \ No newline at end of file +namespace Passingwind.Abp.FileManagement.Files; + +public class FileContainerAdminUpdateDto : FileContainerCreateOrUpdateBasicDto, IHasConcurrencyStamp +{ + public virtual string? ConcurrencyStamp { get; set; } +} \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByBytesDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByBytesDto.cs index 18efb19..556e433 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByBytesDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByBytesDto.cs @@ -16,6 +16,8 @@ public class FileCreateByBytesDto : ExtensibleObject [Required] public byte[] FileData { get; set; } = null!; + public bool Override { get; set; } + public override IEnumerable Validate(ValidationContext validationContext) { foreach (var result in base.Validate(validationContext)) diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByStreamDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByStreamDto.cs index cde3923..8833a77 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByStreamDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateByStreamDto.cs @@ -16,6 +16,8 @@ public class FileCreateByStreamDto : ExtensibleObject [Required] public Stream FileStream { get; set; } = null!; + public bool Override { get; set; } + public override IEnumerable Validate(ValidationContext validationContext) { foreach (var result in base.Validate(validationContext)) diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateDto.cs index 758447c..beffde9 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileCreateDto.cs @@ -10,7 +10,7 @@ public class FileCreateDto : ExtensibleObject { public Guid? ParentId { get; set; } - //public bool Override { get; set; } + public bool Override { get; set; } [Required] public IRemoteStreamContent File { get; set; } = null!; diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveAdminRequestDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveAdminRequestDto.cs new file mode 100644 index 0000000..76e4805 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveAdminRequestDto.cs @@ -0,0 +1,10 @@ +using System; + +namespace Passingwind.Abp.FileManagement.Files; + +public class FileMoveAdminRequestDto +{ + public Guid? TargetId { get; set; } + public Guid? TargetContainerId { get; set; } + public bool Override { get; set; } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveRequestDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveRequestDto.cs index 1580a39..d10474d 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveRequestDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileMoveRequestDto.cs @@ -5,4 +5,5 @@ namespace Passingwind.Abp.FileManagement.Files; public class FileMoveRequestDto { public Guid? TargetId { get; set; } + public bool Override { get; set; } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareListRequestDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareListRequestDto.cs new file mode 100644 index 0000000..2e309ad --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareListRequestDto.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Passingwind.Abp.FileManagement.Files; + +public class FileShareListRequestDto : PagedResultRequestDto +{ + public Guid? FileId { get; set; } +} \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareResultDto.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareResultDto.cs index 06eed39..7020786 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareResultDto.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/FileShareResultDto.cs @@ -4,10 +4,12 @@ namespace Passingwind.Abp.FileManagement.Files; public class FileShareResultDto { + public Guid Id { get; set; } public string FileName { get; set; } = null!; public long Length { get; set; } public string? MimeType { get; set; } - public string DownloadUrl { get; set; } = null!; - public string Token { get; set; } = null!; public DateTime? ExpirationTime { get; set; } + + public string? DirectDownloadUrl { get; set; } + public string? Token { get; set; } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAdminAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAdminAppService.cs new file mode 100644 index 0000000..0279e39 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAdminAppService.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; +using Volo.Abp.Content; + +namespace Passingwind.Abp.FileManagement.Files; + +public interface IFileAdminAppService : IApplicationService +{ + Task> GetListAsync(Guid containerId, FilePagedListRequestDto input); + + Task GetAsync(Guid containerId, Guid id); + + Task CreateDirectoryAsync(Guid containerId, FileDirectoryCreateDto input); + + Task CreateAsync(Guid containerId, FileCreateDto input); + Task CreateByStreamAsync(Guid containerId, FileCreateByStreamDto input); + Task CreateByBytesAsync(Guid containerId, FileCreateByBytesDto input); + + Task UpdateAsync(Guid containerId, Guid id, FileUpdateDto input); + + Task MoveAsync(Guid containerId, Guid id, FileMoveAdminRequestDto input); + + Task GetBlobAsync(Guid containerId, Guid id); + Task GeBlobStreamAsync(Guid containerId, Guid id); + Task GetBlobBytesAsync(Guid containerId, Guid id); + + Task DeleteAsync(Guid containerId, Guid id); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAppService.cs index 28e0070..c9ecabb 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAppService.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileAppService.cs @@ -13,19 +13,17 @@ public interface IFileAppService : IApplicationService Task GetAsync(string containerName, Guid id); - Task GetBlobAsync(string containerName, Guid id); - Task GeBlobStreamAsync(string containerName, Guid id); - Task GetBlobBytesAsync(string containerName, Guid id); - Task CreateDirectoryAsync(string containerName, FileDirectoryCreateDto input); Task CreateAsync(string containerName, FileCreateDto input); Task CreateByStreamAsync(string containerName, FileCreateByStreamDto input); Task CreateByBytesAsync(string containerName, FileCreateByBytesDto input); - Task UpdateAsync(string containerName, Guid id, FileUpdateDto input); + Task RenameAsync(string containerName, Guid id, FileUpdateDto input); Task MoveAsync(string containerName, Guid id, FileMoveRequestDto input); - Task DeleteAsync(string containerName, Guid id); + Task GetBlobAsync(string containerName, Guid id); + Task GeBlobStreamAsync(string containerName, Guid id); + Task GetBlobBytesAsync(string containerName, Guid id); } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAdminAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAdminAppService.cs new file mode 100644 index 0000000..414666b --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAdminAppService.cs @@ -0,0 +1,21 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Passingwind.Abp.FileManagement.Files; + +public interface IFileContainerAdminAppService : IApplicationService +{ + Task> GetAllListAsync(); + + Task> GetListAsync(FileContainerAdminListRequestDto input); + + Task GetAsync(Guid id); + + Task CreateAsync(FileContainerAdminCreateDto input); + + Task UpdateAsync(Guid id, FileContainerAdminUpdateDto input); + + Task DeleteAsync(Guid id); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAppService.cs index 20bfe36..1bb6bd0 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAppService.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileContainerAppService.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; @@ -7,17 +6,9 @@ namespace Passingwind.Abp.FileManagement.Files; public interface IFileContainerAppService : IApplicationService { - Task> GetAllListAsync(); + Task> GetAllListAsync(FileContainerListRequestDto input); - Task> GetListAsync(FileContainerListRequestDto input); + Task GetByNameAsync(string name); - Task GetAsync(Guid id); - - Task GetByNameAsync(string name); - - Task CreateAsync(FileContainerCreateDto input); - - Task UpdateAsync(Guid id, FileContainerUpdateDto input); - - Task DeleteAsync(Guid id); + Task GetCanAccessAsync(string name); } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileIntegrationAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileIntegrationAppService.cs deleted file mode 100644 index 148626d..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileIntegrationAppService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Application.Services; - -namespace Passingwind.Abp.FileManagement.Files; - -[IntegrationService] -public interface IFileIntegrationAppService : IApplicationService -{ - Task GetContainerAsync(Guid id); - - Task GetAsync(string containerName, Guid id); - - Task GetStreamAsync(string containerName, Guid id); - Task GetBytesAsync(string containerName, Guid id); - - Task CreateByStreamAsync(string containerName, FileCreateByStreamDto input); - Task CreateByBytesAsync(string containerName, FileCreateByBytesDto input); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileShareAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileShareAppService.cs index e124ee7..9cbadd4 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileShareAppService.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Files/IFileShareAppService.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Content; @@ -8,9 +9,15 @@ namespace Passingwind.Abp.FileManagement.Files; public interface IFileShareAppService : IApplicationService { + Task> GetListAsync(string containerName, FileShareListRequestDto input); + Task CreateAsync(string containerName, Guid id, FileShareCreateRequestDto input); - Task GetAsync(string token); + Task GetAsync(Guid id); + + Task DeleteAsync(Guid id); + + Task VerifyTokenAsync(string token); Task GetBlobAsync(string token); diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissionDefinitionProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissionDefinitionProvider.cs index 06f62de..9960fe4 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissionDefinitionProvider.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissionDefinitionProvider.cs @@ -11,13 +11,16 @@ public override void Define(IPermissionDefinitionContext context) { var fileManagement = context.AddGroup(FileManagementPermissions.GroupName, L($"Permission:{FileManagementPermissions.GroupName}")); - var fileContainer = fileManagement.AddPermission(FileManagementPermissions.FileContainer.Default, L($"Permission:{FileManagementPermissions.FileContainer.Default}")); - fileContainer.AddChild(FileManagementPermissions.FileContainer.Create, L("Permission:Create")); - fileContainer.AddChild(FileManagementPermissions.FileContainer.Update, L("Permission:Update")); - fileContainer.AddChild(FileManagementPermissions.FileContainer.Delete, L("Permission:Delete")); + var fileContainer = fileManagement.AddPermission(FileManagementPermissions.FileContainers.Default, L($"Permission:{FileManagementPermissions.FileContainers.Default}")); + fileContainer.AddChild(FileManagementPermissions.FileContainers.Create, L("Permission:Create")); + fileContainer.AddChild(FileManagementPermissions.FileContainers.Update, L("Permission:Update")); + fileContainer.AddChild(FileManagementPermissions.FileContainers.Delete, L("Permission:Delete")); - var file = fileManagement.AddPermission(FileManagementPermissions.File.Default, L($"Permission:{FileManagementPermissions.File.Default}")); - file.AddChild(FileManagementPermissions.File.Delete, L("Permission:Delete")); + var file = fileManagement.AddPermission(FileManagementPermissions.Files.Default, L($"Permission:{FileManagementPermissions.Files.Default}")); + file.AddChild(FileManagementPermissions.Files.Delete, L("Permission:Delete")); + file.AddChild(FileManagementPermissions.Files.Update, L("Permission:Update")); + file.AddChild(FileManagementPermissions.Files.Upload, L($"Permission:{FileManagementPermissions.Files.Default}.Upload")); + file.AddChild(FileManagementPermissions.Files.Download, L($"Permission:{FileManagementPermissions.Files.Default}.Download")); } private static LocalizableString L(string name) diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissions.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissions.cs index 552c5d2..3edf386 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissions.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application.Contracts/Permissions/FileManagementPermissions.cs @@ -6,7 +6,7 @@ public class FileManagementPermissions { public const string GroupName = "FileManagement"; - public static class FileContainer + public static class FileContainers { public const string Default = GroupName + ".FileContainer"; public const string Create = Default + ".Create"; @@ -14,10 +14,13 @@ public static class FileContainer public const string Delete = Default + ".Delete"; } - public static class File + public static class Files { public const string Default = GroupName + ".File"; + public const string Update = GroupName + ".Update"; public const string Delete = Default + ".Delete"; + public const string Upload = GroupName + ".Upload"; + public const string Download = GroupName + ".Download"; } public static string[] GetAll() diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAdminAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAdminAppService.cs new file mode 100644 index 0000000..f5b3970 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAdminAppService.cs @@ -0,0 +1,268 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement.Files; +using Passingwind.Abp.FileManagement.Options; +using Passingwind.Abp.FileManagement.Permissions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.Domain.Entities; +using Volo.Abp.ObjectExtending; + +namespace Passingwind.Abp.FileManagement; + +[Authorize(FileManagementPermissions.Files.Default)] +public class FileAdminAppService : FileManagementAppService, IFileAdminAppService +{ + protected FileManagementOptions FileManagementOptions { get; } + protected IFileManager FileManager { get; } + protected IFileRepository FileRepository { get; } + protected IFileContainerRepository FileContainerRepository { get; } + protected IFileContainerManager FileContainerManager { get; } + protected IFileMimeTypeProvider FileMimeTypeProvider { get; } + + public FileAdminAppService( + IOptions fileManagementOptions, + IFileManager fileManager, + IFileRepository fileRepository, + IFileContainerRepository fileContainerRepository, + IFileContainerManager fileContainerManager, + IFileMimeTypeProvider fileMimeTypeProvider) + { + FileManagementOptions = fileManagementOptions.Value; + FileManager = fileManager; + FileRepository = fileRepository; + FileContainerRepository = fileContainerRepository; + FileContainerManager = fileContainerManager; + FileMimeTypeProvider = fileMimeTypeProvider; + } + + public virtual async Task> GetListAsync(Guid containerId, FilePagedListRequestDto input) + { + var count = await FileRepository.GetCountAsync( + filter: input.Filter, + containerId: containerId, + parentId: input.ParentId ?? Guid.Empty, + isDirectory: input.IsDirectory); + var list = await FileRepository.GetPagedListAsync( + input.SkipCount, + input.MaxResultCount, + input.Filter, + containerId: containerId, + parentId: input.ParentId ?? Guid.Empty, + isDirectory: input.IsDirectory, + sorting: input.Sorting ?? $"{nameof(FileItem.IsDirectory)} desc,{nameof(FileItem.FileName)}"); + + return new PagedResultDto() + { + Items = ObjectMapper.Map, List>(list), + TotalCount = count, + }; + } + + public virtual async Task GetAsync(Guid containerId, Guid id) + { + var entity = await FileRepository.GetAsync(id); + + return containerId != entity.ContainerId ? throw new EntityNotFoundException() : ObjectMapper.Map(entity); + } + + [Authorize(FileManagementPermissions.Files.Delete)] + public virtual async Task DeleteAsync(Guid containerId, Guid id) + { + var entity = await FileRepository.GetAsync(id); + + if (entity.IsDirectory) + { + // TODO delete files + } + + await FileRepository.DeleteAsync(entity); + } + + [Authorize(FileManagementPermissions.Files.Download)] + public virtual async Task GetBlobAsync(Guid containerId, Guid id) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var entity = await FileRepository.GetAsync(id); + + if (containerId != entity.ContainerId || entity.IsDirectory) + { + throw new EntityNotFoundException(); + } + + var fileStream = await FileManager.GetFileSteamAsync(container.Id, id); + + return fileStream == null + ? throw new BlobNotFoundException() + : new RemoteStreamContent(fileStream, entity.FileName, entity.MimeType); + } + + [Authorize(FileManagementPermissions.Files.Download)] + public virtual async Task GeBlobStreamAsync(Guid containerId, Guid id) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var entity = await FileRepository.GetAsync(id); + + return containerId != entity.ContainerId || entity.IsDirectory + ? throw new EntityNotFoundException() + : await FileManager.GetFileSteamAsync(container.Id, id); + } + + [Authorize(FileManagementPermissions.Files.Download)] + public virtual async Task GetBlobBytesAsync(Guid containerId, Guid id) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var entity = await FileRepository.GetAsync(id); + + return containerId != entity.ContainerId || entity.IsDirectory + ? throw new EntityNotFoundException() + : await FileManager.GetFileBytesAsync(container.Id, id); + } + + [Authorize(FileManagementPermissions.Files.Upload)] + public virtual async Task CreateAsync(Guid containerId, FileCreateDto input) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var fileBytes = await input.File.GetStream().GetAllBytesAsync(); + + var entity = await CreateFileAsync(container, fileName: input.File.FileName!, parentId: input.ParentId ?? Guid.Empty, mimeType: null, fileBytes: fileBytes, overExists: input.Override, extensibleObject: input); + + return ObjectMapper.Map(entity); + } + + [Authorize(FileManagementPermissions.Files.Upload)] + public virtual async Task CreateByStreamAsync(Guid containerId, FileCreateByStreamDto input) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var bytes = await input.FileStream.GetAllBytesAsync(); + + var entity = await CreateFileAsync(container, fileName: input.FileName, parentId: input.ParentId ?? Guid.Empty, mimeType: input.MimeType, fileBytes: bytes, overExists: input.Override, extensibleObject: input); + + return ObjectMapper.Map(entity); + } + + [Authorize(FileManagementPermissions.Files.Upload)] + public virtual async Task CreateByBytesAsync(Guid containerId, FileCreateByBytesDto input) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var bytes = input.FileData; + + var entity = await CreateFileAsync(container, fileName: input.FileName, parentId: input.ParentId ?? Guid.Empty, mimeType: input.MimeType, fileBytes: bytes, overExists: input.Override, extensibleObject: input); + + return ObjectMapper.Map(entity); + } + + [Authorize(FileManagementPermissions.Files.Update)] + public virtual async Task MoveAsync(Guid containerId, Guid id, FileMoveAdminRequestDto input) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var entity = await FileRepository.GetAsync(id); + + if (input.TargetId.HasValue && entity.ParentId != input.TargetId) + { + var target = await FileManager.FindAsync(input.TargetId.Value); + + if (target?.IsDirectory != false) + { + throw new EntityNotFoundException(typeof(FileItem), input.TargetId); + } + + entity.ChangeParentId(input.TargetId ?? Guid.Empty); + } + + if (input.TargetContainerId.HasValue && entity.ContainerId != input.TargetContainerId) + { + await FileContainerRepository.GetAsync(input.TargetContainerId.Value); + + entity.ChangeContainerId(input.TargetContainerId ?? Guid.Empty); + } + + if (!input.Override && await FileManager.IsFileExistsAsync(container.Id, entity.FileName, entity.ParentId)) + { + throw new BusinessException(FileManagementErrorCodes.FileExists); + } + + await FileRepository.UpdateAsync(entity); + + return ObjectMapper.Map(entity); + } + + [Authorize(FileManagementPermissions.Files.Update)] + public virtual async Task UpdateAsync(Guid containerId, Guid id, FileUpdateDto input) + { + var container = await FileContainerRepository.GetAsync(containerId); + + var entity = await FileRepository.GetAsync(id); + + if (entity.FileName != input.FileName) + { + if (await FileManager.IsExistsAsync(container.Id, input.FileName, parentId: entity.ParentId)) + { + throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", input.FileName); + } + + entity.SetFileName(input.FileName); + + input.MapExtraPropertiesTo(entity); + + await FileRepository.UpdateAsync(entity); + } + + return ObjectMapper.Map(entity); + } + + public virtual async Task CreateDirectoryAsync(Guid containerId, FileDirectoryCreateDto input) + { + await FileContainerRepository.GetAsync(containerId); + + var exists = await FileManager.IsDirectoryExistsAsync(containerId, input.FileName, parentId: input.ParentId); + if (!input.Force && exists) + { + throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", input.FileName); + } + + FileItem entity; + if (exists) + { + entity = await FileRepository.GetByNameAsync(containerId, input.FileName, parentId: input.ParentId, isDirectory: true); + } + else + { + entity = await FileManager.CreateDirectoryAsync(containerId, input.FileName, parentId: input.ParentId); + await CurrentUnitOfWork.SaveChangesAsync(); + } + + input.MapExtraPropertiesTo(entity); + + entity = await FileRepository.UpdateAsync(entity!); + + return ObjectMapper.Map(entity); + } + + protected virtual async Task CreateFileAsync(FileContainer container, string fileName, Guid parentId, string? mimeType, byte[] fileBytes, bool overExists = false, ExtensibleObject? extensibleObject = null) + { + mimeType ??= FileMimeTypeProvider.Get(fileName); + + var entity = await FileManager.SaveAsync(containerId: container.Id, fileName: fileName, bytes: fileBytes, mimeType: mimeType, parentId: parentId, overrideExisting: overExists); + + await CurrentUnitOfWork.SaveChangesAsync(); + + extensibleObject.MapExtraPropertiesTo(entity); + + await FileRepository.UpdateAsync(entity); + + return entity; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAppService.cs new file mode 100644 index 0000000..87a0585 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileAppService.cs @@ -0,0 +1,307 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement.Files; +using Passingwind.Abp.FileManagement.Options; +using Passingwind.Abp.FileManagement.Permissions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.Domain.Entities; +using Volo.Abp.ObjectExtending; + +namespace Passingwind.Abp.FileManagement; + +[AllowAnonymous] +public class FileAppService : FileManagementAppService, IFileAppService +{ + protected FileManagementOptions FileManagementOptions { get; } + protected IFileManager FileManager { get; } + protected IFileRepository FileRepository { get; } + protected IFileContainerRepository FileContainerRepository { get; } + protected IFileContainerManager FileContainerManager { get; } + protected IFileMimeTypeProvider FileMimeTypeProvider { get; } + protected IFileRenameProvider FileRenameProvider { get; } + + public FileAppService( + IOptions fileManagementOptions, + IFileManager fileManager, + IFileRepository fileRepository, + IFileContainerRepository fileContainerRepository, + IFileContainerManager fileContainerManager, + IFileMimeTypeProvider fileMimeTypeProvider, + IFileRenameProvider fileRenameProvider) + { + FileManagementOptions = fileManagementOptions.Value; + FileManager = fileManager; + FileRepository = fileRepository; + FileContainerRepository = fileContainerRepository; + FileContainerManager = fileContainerManager; + FileMimeTypeProvider = fileMimeTypeProvider; + FileRenameProvider = fileRenameProvider; + } + + public virtual async Task> GetListAsync(string containerName, FilePagedListRequestDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container); + + var count = await FileRepository.GetCountAsync( + filter: input.Filter, + containerId: container.Id, + parentId: input.ParentId ?? Guid.Empty, + isDirectory: input.IsDirectory); + + var list = await FileRepository.GetPagedListAsync( + input.SkipCount, + input.MaxResultCount, + input.Filter, + containerId: container.Id, + parentId: input.ParentId ?? Guid.Empty, + isDirectory: input.IsDirectory, + sorting: input.Sorting ?? $"{nameof(FileItem.IsDirectory)} desc, {nameof(FileItem.FileName)}"); + + return new PagedResultDto() + { + Items = ObjectMapper.Map, List>(list), + TotalCount = count, + }; + } + + public virtual async Task GetAsync(string containerName, Guid id) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container); + + var entity = await FileRepository.GetAsync(id); + + await CheckFileIsInContainerAsync(container, entity); + + return ObjectMapper.Map(entity); + } + + public virtual async Task GetBlobAsync(string containerName, Guid id) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container); + + var entity = await FileRepository.GetAsync(id); + + await CheckFileIsInContainerAsync(container, entity); + + var fileStream = await FileManager.GetFileSteamAsync(container.Id, id); + + return fileStream == null + ? throw new BlobNotFoundException() + : new RemoteStreamContent(fileStream, entity.FileName, entity.MimeType); + } + + public virtual async Task GeBlobStreamAsync(string containerName, Guid id) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container); + + var entity = await FileRepository.GetAsync(id); + + await CheckFileIsInContainerAsync(container, entity); + + return await FileManager.GetFileSteamAsync(container.Id, id); + } + + public virtual async Task GetBlobBytesAsync(string containerName, Guid id) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container); + + var entity = await FileRepository.GetAsync(id); + + await CheckFileIsInContainerAsync(container, entity); + + return await FileManager.GetFileBytesAsync(container.Id, id); + } + + public virtual async Task CreateAsync(string containerName, FileCreateDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container, write: true); + + var fileBytes = await input.File.GetStream().GetAllBytesAsync(); + + var entity = await CreateFileAsync(container, fileName: input.File.FileName!, parentId: input.ParentId ?? Guid.Empty, mimeType: null, fileBytes: fileBytes, overExists: input.Override, extensibleObject: input); + + return ObjectMapper.Map(entity); + } + + public virtual async Task CreateByStreamAsync(string containerName, FileCreateByStreamDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container, write: true); + + var bytes = await input.FileStream.GetAllBytesAsync(); + + var entity = await CreateFileAsync(container, fileName: input.FileName!, parentId: input.ParentId ?? Guid.Empty, mimeType: null, fileBytes: bytes, overExists: input.Override, extensibleObject: input); + + return ObjectMapper.Map(entity); + } + + public virtual async Task CreateByBytesAsync(string containerName, FileCreateByBytesDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container, write: true); + + var bytes = input.FileData; + + var entity = await CreateFileAsync(container, fileName: input.FileName!, parentId: input.ParentId ?? Guid.Empty, mimeType: null, fileBytes: bytes, overExists: input.Override, extensibleObject: input); + + return ObjectMapper.Map(entity); + } + + public virtual async Task MoveAsync(string containerName, Guid id, FileMoveRequestDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container, write: true); + + var entity = await FileRepository.GetAsync(id); + + await CheckFileIsInContainerAsync(container, entity); + + if (input.TargetId.HasValue && entity.ParentId != input.TargetId) + { + var target = await FileManager.FindAsync(input.TargetId.Value); + + if (target?.IsDirectory != false) + { + throw new EntityNotFoundException(typeof(FileItem), input.TargetId); + } + + entity.ChangeParentId(input.TargetId ?? Guid.Empty); + } + + if (!input.Override && await FileManager.IsFileExistsAsync(container.Id, entity.FileName, entity.ParentId)) + { + throw new BusinessException(FileManagementErrorCodes.FileExists); + } + + await FileRepository.UpdateAsync(entity); + + return ObjectMapper.Map(entity); + } + + public virtual async Task RenameAsync(string containerName, Guid id, FileUpdateDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container); + + var entity = await FileRepository.GetAsync(id); + + if (entity.FileName != input.FileName) + { + if (await FileManager.IsExistsAsync(container.Id, input.FileName, parentId: entity.ParentId)) + { + throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", input.FileName); + } + + entity.SetFileName(input.FileName); + + input.MapExtraPropertiesTo(entity); + + await FileRepository.UpdateAsync(entity); + } + + return ObjectMapper.Map(entity); + } + + public virtual async Task CreateDirectoryAsync(string containerName, FileDirectoryCreateDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + var exists = await FileManager.IsDirectoryExistsAsync(container.Id, input.FileName, parentId: input.ParentId); + if (!input.Force && exists) + { + throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", input.FileName); + } + + FileItem entity; + if (exists) + { + entity = await FileRepository.GetByNameAsync(container.Id, input.FileName, parentId: input.ParentId, isDirectory: true); + } + else + { + entity = await FileManager.CreateDirectoryAsync(container.Id, input.FileName, parentId: input.ParentId); + await CurrentUnitOfWork.SaveChangesAsync(); + } + + input.MapExtraPropertiesTo(entity); + + entity = await FileRepository.UpdateAsync(entity); + + return ObjectMapper.Map(entity); + } + + protected virtual async Task CreateFileAsync(FileContainer container, string fileName, Guid parentId, string? mimeType, byte[] fileBytes, bool overExists = false, ExtensibleObject? extensibleObject = null) + { + mimeType ??= FileMimeTypeProvider.Get(fileName); + + var entity = await FileManager.SaveAsync(containerId: container.Id, fileName: fileName, bytes: fileBytes, mimeType: mimeType, parentId: parentId, overrideExisting: overExists); + + await CurrentUnitOfWork.SaveChangesAsync(); + + extensibleObject.MapExtraPropertiesTo(entity); + + await FileRepository.UpdateAsync(entity); + + return entity; + } + + /// + /// Check current identity can access this container + /// + /// + /// + protected override async Task CanAccessContainerAsync(FileContainer container, bool write = false) + { + var isGranted = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainers.Default); + + if (isGranted) + { + return true; + } + + if (container.AccessMode == FileAccessMode.Anonymous) + { + return true; + } + else if (container.AccessMode == FileAccessMode.AnonymousReadonly && !write) + { + return true; + } + else if (container.AccessMode == FileAccessMode.Authorized && CurrentUser.IsAuthenticated) + { + return true; + } + else + { + // private & owner + return container.CreatorId == CurrentUser.Id; + } + } + + protected virtual async Task CheckContainerPermissionAsync(string containerName, string? policyName = null, bool write = false) + { + await CheckContainerPermissionAsync(FileContainerRepository, containerName, policyName, write); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAdminAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAdminAppService.cs new file mode 100644 index 0000000..39ed81e --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAdminAppService.cs @@ -0,0 +1,132 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement.Files; +using Passingwind.Abp.FileManagement.Options; +using Passingwind.Abp.FileManagement.Permissions; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.ObjectExtending; + +namespace Passingwind.Abp.FileManagement; + +[Authorize(FileManagementPermissions.FileContainers.Default)] +public class FileContainerAdminAppService : FileManagementAppService, IFileContainerAdminAppService +{ + protected FileManagementOptions FileManagementOptions { get; } + protected IFileContainerManager FileContainerManager { get; } + protected IFileContainerRepository FileContainerRepository { get; } + protected IFileRepository FileRepository { get; } + protected IFileManager FileManager { get; } + + public FileContainerAdminAppService( + IOptions fileManagementOptions, + IFileContainerManager fileContainerManager, + IFileContainerRepository fileContainerRepository, + IFileRepository fileRepository, + IFileManager fileManager) + { + FileManagementOptions = fileManagementOptions.Value; + FileContainerManager = fileContainerManager; + FileContainerRepository = fileContainerRepository; + FileRepository = fileRepository; + FileManager = fileManager; + } + + public virtual async Task> GetAllListAsync() + { + // return all list + var list = await FileContainerRepository.GetListAsync(); + + return new ListResultDto(ObjectMapper.Map, List>(list)); + } + + public virtual async Task> GetListAsync(FileContainerAdminListRequestDto input) + { + var count = await FileContainerRepository.GetCountAsync(input.Filter); + var list = await FileContainerRepository.GetPagedListAsync(input.SkipCount, input.MaxResultCount, input.Filter, sorting: nameof(FileContainer.Name)); + + return new PagedResultDto() + { + Items = ObjectMapper.Map, List>(list), + TotalCount = count, + }; + } + + public virtual async Task GetAsync(Guid id) + { + var entity = await FileContainerRepository.GetAsync(id); + + return ObjectMapper.Map(entity); + } + + public virtual async Task CreateAsync(FileContainerAdminCreateDto input) + { + var entity = await FileContainerManager.CreateAsync( + name: input.Name, + accessMode: input.AccessMode ?? FileManagementOptions.DefaultContainerAccessMode, + overrideBehavior: input.OverrideBehavior ?? FileManagementOptions.DefaultOverrideBehavior, + description: input.Description, + maximumEachFileSize: input.MaximumEachFileSize, + maximumFileQuantity: input.MaximumFileQuantity, + allowAnyFileExtension: input.AllowAnyFileExtension, + allowedFileExtensions: input.AllowedFileExtensions, + prohibitedFileExtensions: input.ProhibitedFileExtensions, + autoDeleteBlob: input.AutoDeleteBlob); + + input.MapExtraPropertiesTo(entity); + + if (await FileContainerManager.IsExistsAsync(entity)) + { + throw new BusinessException(FileManagementErrorCodes.ContainerExist).WithData("name", entity.Name); + } + + entity = await FileContainerRepository.InsertAsync(entity); + + return ObjectMapper.Map(entity); + } + + public virtual async Task UpdateAsync(Guid id, FileContainerAdminUpdateDto input) + { + var entity = await FileContainerRepository.GetAsync(id); + + entity.Description = input.Description; + entity.MaximumEachFileSize = input.MaximumEachFileSize ?? 0; + entity.MaximumFileQuantity = input.MaximumFileQuantity ?? 0; + entity.OverrideBehavior = input.OverrideBehavior ?? FileOverrideBehavior.None; + entity.AllowAnyFileExtension = input.AllowAnyFileExtension ?? false; + entity.AllowedFileExtensions = input.AllowedFileExtensions; + entity.ProhibitedFileExtensions = input.ProhibitedFileExtensions; + entity.AutoDeleteBlob = input.AutoDeleteBlob; + + entity.ConcurrencyStamp = input.ConcurrencyStamp; + + entity.SetAccessMode(input.AccessMode ?? FileManagementOptions.DefaultContainerAccessMode); + + input.MapExtraPropertiesTo(entity); + + entity = await FileContainerRepository.UpdateAsync(entity); + + return ObjectMapper.Map(entity); + } + + public virtual async Task DeleteAsync(Guid id) + { + var entity = await FileContainerRepository.GetAsync(id); + + var fileCount = await FileRepository.GetCountAsync(containerId: id); + + if (fileCount > 0 && !FileManagementOptions.AllowForceDeleteContainer) + { + throw new BusinessException(FileManagementErrorCodes.ContainerNotAllowForceDelete); + } + + // 1. delete file + await FileManager.ClearContainerFilesAsync(entity.Id); + + // 2. delete container + await FileContainerRepository.DeleteAsync(id); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAppService.cs new file mode 100644 index 0000000..0c9be1f --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileContainerAppService.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Authorization; +using Passingwind.Abp.FileManagement.Files; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; + +namespace Passingwind.Abp.FileManagement; + +[Authorize] +public class FileContainerAppService : FileManagementAppService, IFileContainerAppService +{ + protected IFileContainerManager FileContainerManager { get; } + protected IFileContainerRepository FileContainerRepository { get; } + + public FileContainerAppService(IFileContainerManager fileContainerManager, IFileContainerRepository fileContainerRepository) + { + FileContainerManager = fileContainerManager; + FileContainerRepository = fileContainerRepository; + } + + public virtual async Task> GetAllListAsync(FileContainerListRequestDto input) + { + var list = await FileContainerRepository.GetListAsync(); + + // TODO + + return new ListResultDto(ObjectMapper.Map, List>(list)); + } + + public virtual async Task GetByNameAsync(string name) + { + var entity = await FileContainerRepository.GetByNameAsync(name); + + return ObjectMapper.Map(entity); + } + + public virtual async Task GetCanAccessAsync(string name) + { + _ = await FileContainerRepository.GetByNameAsync(name); + + // TODO + + return new FileContainerCanAccessResultDto { Result = false }; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementAppService.cs index b308abc..20f4be0 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementAppService.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementAppService.cs @@ -1,8 +1,8 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Passingwind.Abp.FileManagement.Files; using Passingwind.Abp.FileManagement.Localization; using Passingwind.Abp.FileManagement.Permissions; +using System.Threading.Tasks; using Volo.Abp.Application.Services; using Volo.Abp.Authorization; using Volo.Abp.Domain.Entities; @@ -24,16 +24,18 @@ protected FileManagementAppService() /// protected virtual async Task CanAccessContainerAsync(FileContainer container, bool write = false) { - bool isGranted = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Default); + bool isGranted = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainers.Default); if (isGranted) + { return true; + } if (container.AccessMode == FileAccessMode.Anonymous) { return true; } - else if (container.AccessMode == FileAccessMode.Readonly && !write) + else if (container.AccessMode == FileAccessMode.AnonymousReadonly && !write) { return true; } @@ -63,7 +65,7 @@ protected virtual async Task CheckContainerPermissionAsync(IFileContainerReposit if (!await CanAccessContainerAsync(container, write)) { throw new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGrantedWithPolicyName) - .WithData("PolicyName", policyName ?? FileManagementPermissions.FileContainer.Default); + .WithData("PolicyName", policyName ?? FileManagementPermissions.FileContainers.Default); } } @@ -79,11 +81,11 @@ protected virtual async Task CheckContainerPermissionAsync(FileContainer contain if (!await CanAccessContainerAsync(container, write)) { throw new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGrantedWithPolicyName) - .WithData("PolicyName", policyName ?? FileManagementPermissions.FileContainer.Default); + .WithData("PolicyName", policyName ?? FileManagementPermissions.FileContainers.Default); } } - protected virtual Task CheckFileIsInContainerAsync(FileContainer container, File file) + protected virtual Task CheckFileIsInContainerAsync(FileContainer container, FileItem file) { if (file.IsDirectory) { @@ -91,9 +93,6 @@ protected virtual Task CheckFileIsInContainerAsync(FileContainer container, File throw new EntityNotFoundException(); } - if (container.Id != file.ContainerId) - throw new EntityNotFoundException(); - - return Task.CompletedTask; + return container.Id != file.ContainerId ? throw new EntityNotFoundException() : Task.CompletedTask; } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementApplicationAutoMapperProfile.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementApplicationAutoMapperProfile.cs index 9de9ff2..1eb2e11 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementApplicationAutoMapperProfile.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileManagementApplicationAutoMapperProfile.cs @@ -12,6 +12,7 @@ public FileManagementApplicationAutoMapperProfile() * into multiple profile classes for a better organization. */ CreateMap(); - CreateMap(); + CreateMap(); + CreateMap(); } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileShareAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileShareAppService.cs new file mode 100644 index 0000000..c22a0ce --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/FileShareAppService.cs @@ -0,0 +1,221 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement.Files; +using Passingwind.Abp.FileManagement.Options; +using System; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Users; + +namespace Passingwind.Abp.FileManagement; + +[Authorize] +public class FileShareAppService : FileManagementAppService, IFileShareAppService +{ + protected IFileManager FileManager { get; } + protected IFileRepository FileRepository { get; } + protected IFileContainerRepository FileContainerRepository { get; } + protected IFileAccessTokenProvider FileAccessTokenProvider { get; } + protected IFileAccessTokenRepository FileAccessTokenRepository { get; } + protected FileManagementOptions FileManagementOptions { get; } + + public FileShareAppService( + IFileManager fileManager, + IFileRepository fileRepository, + IFileContainerRepository fileContainerRepository, + IFileAccessTokenProvider fileAccessTokenProvider, + IOptions options, + IFileAccessTokenRepository fileAccessTokenRepository) + { + FileManager = fileManager; + FileRepository = fileRepository; + FileContainerRepository = fileContainerRepository; + FileAccessTokenProvider = fileAccessTokenProvider; + FileManagementOptions = options.Value; + FileAccessTokenRepository = fileAccessTokenRepository; + } + + public virtual async Task> GetListAsync(string containerName, FileShareListRequestDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + var userId = CurrentUser.GetId(); + + var count = await FileAccessTokenRepository.GetCountAsync(container.Id, fileId: input.FileId, userId: userId); + var list = await FileAccessTokenRepository.GetPagedListAsync(input.SkipCount, input.MaxResultCount, container.Id, fileId: input.FileId, userId: userId); + + return new PagedResultDto(count, list.ConvertAll(x => new FileShareResultDto + { + Id = x.Id, + FileName = x.FileName, + Length = x.Length, + MimeType = x.MimeType, + ExpirationTime = x.ExpirationTime, + Token = x.Token, + DirectDownloadUrl = GetDownloadUrl(x.Token, containerName), + })); + } + + public virtual async Task GetAsync(Guid id) + { + var entity = await FileAccessTokenRepository.GetAsync(id); + + if (entity.CreatorId != CurrentUser.Id) + { + throw new EntityNotFoundException(); + } + + var file = await FileManager.GetAsync(entity.FileId); + + var container = await FileContainerRepository.GetAsync(file.ContainerId); + + return new FileShareResultDto + { + Id = entity.Id, + FileName = entity.FileName, + Length = entity.Length, + MimeType = entity.MimeType, + ExpirationTime = entity.ExpirationTime, + Token = entity.Token, + DirectDownloadUrl = GetDownloadUrl(entity.Token, container.Name), + }; + } + + public virtual async Task DeleteAsync(Guid id) + { + var entity = await FileAccessTokenRepository.GetAsync(id); + + if (entity.CreatorId != CurrentUser.Id) + { + throw new EntityNotFoundException(); + } + + await FileAccessTokenRepository.DeleteAsync(entity); + } + + public virtual async Task CreateAsync(string containerName, Guid id, FileShareCreateRequestDto input) + { + var container = await FileContainerRepository.GetByNameAsync(containerName); + + await CheckContainerPermissionAsync(container); + + var fileItem = await FileRepository.GetAsync(id); + + await CheckFileIsInContainerAsync(container, fileItem); + + TimeSpan? expiration = input.ExpirationSecond.HasValue ? TimeSpan.FromSeconds(input.ExpirationSecond.Value) : null; + + var entity = await FileManager.CreateAccessTokenAsync(container.Id, id, expiration); + + return new FileShareResultDto + { + Id = entity.Id, + FileName = entity.FileName, + Length = entity.Length, + MimeType = entity.MimeType, + ExpirationTime = entity.ExpirationTime, + + DirectDownloadUrl = GetDownloadUrl(entity.Token, container.Name), + Token = entity.Token, + }; + } + + [AllowAnonymous] + public virtual async Task VerifyTokenAsync(string token) + { + var validationResult = await FileAccessTokenProvider.VerifyAsync(token); + + if (!validationResult.IsValid || validationResult.File == null) + { + throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); + } + + var file = validationResult.File; + + return new FileShareResultDto + { + Id = validationResult.TokenId, + FileName = file.FileName, + Length = file.Length, + MimeType = file.MimeType, + ExpirationTime = validationResult.ExpirationTime, + }; + } + + [AllowAnonymous] + public virtual async Task GetAsync(string token) + { + var validationResult = await FileAccessTokenProvider.VerifyAsync(token); + + if (!validationResult.IsValid || validationResult.File == null) + { + throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); + } + + var file = validationResult.File; + + return new FileShareResultDto + { + FileName = file.FileName, + Length = file.Length, + MimeType = file.MimeType, + ExpirationTime = validationResult.ExpirationTime, + }; + } + + [AllowAnonymous] + public virtual async Task GetBlobAsync(string token) + { + var validationResult = await FileAccessTokenProvider.VerifyAsync(token); + + if (!validationResult.IsValid || validationResult.File == null) + { + throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); + } + + var file = validationResult.File; + + var fileStream = await FileManager.GetFileSteamAsync(file.ContainerId, file.Id); + + return fileStream == null ? throw new BlobNotFoundException() : new RemoteStreamContent(fileStream, file.FileName, file.MimeType); + } + + [AllowAnonymous] + public virtual async Task GetBytesAsync(string token) + { + var validationResult = await FileAccessTokenProvider.VerifyAsync(token); + + if (!validationResult.IsValid || validationResult.File == null) + { + throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); + } + + var file = validationResult.File; + + return await FileManager.GetFileBytesAsync(file.ContainerId, file.Id); + } + + [AllowAnonymous] + public virtual async Task GetStreamAsync(string token) + { + var validationResult = await FileAccessTokenProvider.VerifyAsync(token); + + if (!validationResult.IsValid || validationResult.File == null) + { + throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); + } + + var file = validationResult.File; + + return await FileManager.GetFileSteamAsync(file.ContainerId, file.Id); + } + + protected virtual string GetDownloadUrl(string token, string containerName) + { + return string.Format(FileManagementOptions.FileShareDownloadUrlFormat, token, containerName); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileAppService.cs deleted file mode 100644 index 3778451..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileAppService.cs +++ /dev/null @@ -1,360 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Options; -using Passingwind.Abp.FileManagement.Options; -using Passingwind.Abp.FileManagement.Permissions; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Content; -using Volo.Abp.Domain.Entities; -using Volo.Abp.ObjectExtending; - -namespace Passingwind.Abp.FileManagement.Files; - -[AllowAnonymous] -public class FileAppService : FileManagementAppService, IFileAppService -{ - protected IFileManager FileManager { get; } - protected IFileRepository FileRepository { get; } - protected IFileContainerRepository FileContainerRepository { get; } - protected FileContainerManager FileContainerManager { get; } - protected IFileInfoCheckProvider FileInfoCheckProvider { get; } - protected IFileMimeTypeProvider FileMimeTypeProvider { get; } - protected IFileRenameProvider FileRenameProvider { get; } - protected IFileAccessTokenProvider FileAccessTokenProvider { get; } - protected FileManagementOptions FileManagementOptions { get; } - - public FileAppService( - IFileManager fileManager, - IFileRepository fileRepository, - IFileContainerRepository fileContainerRepository, - FileContainerManager fileContainerManager, - IFileInfoCheckProvider fileInfoCheckProvider, - IFileMimeTypeProvider fileMimeTypeProvider, - IFileRenameProvider fileRenameProvider, - IFileAccessTokenProvider fileAccessTokenProvider, - IOptions options) - { - FileManager = fileManager; - FileRepository = fileRepository; - FileContainerRepository = fileContainerRepository; - FileContainerManager = fileContainerManager; - FileInfoCheckProvider = fileInfoCheckProvider; - FileMimeTypeProvider = fileMimeTypeProvider; - FileRenameProvider = fileRenameProvider; - FileAccessTokenProvider = fileAccessTokenProvider; - FileManagementOptions = options.Value; - } - - public virtual async Task> GetListAsync(string containerName, FilePagedListRequestDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container); - - long count = await FileRepository.GetCountAsync( - filter: input.Filter, - containerId: container.Id, - parentId: input.ParentId ?? Guid.Empty, - isDirectory: input.IsDirectory); - List list = await FileRepository.GetPagedListAsync( - input.SkipCount, - input.MaxResultCount, - input.Filter, - containerId: container.Id, - parentId: input.ParentId ?? Guid.Empty, - isDirectory: input.IsDirectory, - sorting: input.Sorting ?? $"{nameof(File.IsDirectory)} desc,{nameof(File.FileName)}"); - - return new PagedResultDto() - { - Items = ObjectMapper.Map, List>(list), - TotalCount = count, - }; - } - - public virtual async Task GetAsync(string containerName, Guid id) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container); - - File entity = await FileRepository.GetAsync(id); - - await CheckFileIsInContainerAsync(container, entity); - - return ObjectMapper.Map(entity); - } - - public virtual async Task DeleteAsync(string containerName, Guid id) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - // 1: container permssion - await CheckContainerPermissionAsync(container, write: true); - - //2: file permssion - await AuthorizationService.CheckAsync(FileManagementPermissions.File.Delete); - - File entity = await FileRepository.GetAsync(id); - - if (entity.IsDirectory) - { - // if an directory has files, can't be delete - long fileCount = await FileRepository.GetCountAsync(containerId: container.Id, parentId: entity.Id); - if (fileCount > 0) - { - throw new BusinessException(FileManagementErrorCodes.DirectoryHasFiles).WithData("name", entity.FileName); - } - - await FileRepository.DeleteAsync(entity); - } - else - { - await CheckFileIsInContainerAsync(container, entity); - - await FileManager.DeleteAsync(container, entity); - } - } - - public virtual async Task GetBlobAsync(string containerName, Guid id) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container); - - File entity = await FileRepository.GetAsync(id); - - await CheckFileIsInContainerAsync(container, entity); - - Stream? fileStream = await FileManager.GetFileSteamAsync(container, entity); - - return fileStream == null - ? throw new BlobNotFoundException() - : (IRemoteStreamContent)new RemoteStreamContent(fileStream, entity.FileName, entity.MimeType); - } - - public virtual async Task GeBlobStreamAsync(string containerName, Guid id) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container); - - File entity = await FileRepository.GetAsync(id); - - await CheckFileIsInContainerAsync(container, entity); - - return await FileManager.GetFileSteamAsync(container, entity); - } - - public virtual async Task GetBlobBytesAsync(string containerName, Guid id) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container); - - File entity = await FileRepository.GetAsync(id); - - await CheckFileIsInContainerAsync(container, entity); - - return await FileManager.GetFileBytesAsync(container, entity); - } - - public virtual async Task CreateAsync(string containerName, FileCreateDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container, write: true); - - byte[] fileBytes = await input.File.GetStream().GetAllBytesAsync(); - - File entity = await CreateFileAsync(container, input.File.FileName!, input.ParentId, null, fileBytes, input); - - return ObjectMapper.Map(entity); - } - - public virtual async Task CreateByStreamAsync(string containerName, FileCreateByStreamDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container, write: true); - - byte[] bytes = await input.FileStream.GetAllBytesAsync(); - - File entity = await CreateFileAsync(container, input.FileName, input.ParentId, input.MimeType, bytes, input); - - return ObjectMapper.Map(entity); - } - - public virtual async Task CreateByBytesAsync(string containerName, FileCreateByBytesDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container, write: true); - - byte[] bytes = input.FileData; - - File entity = await CreateFileAsync(container, input.FileName, input.ParentId, input.MimeType, bytes, input); - - return ObjectMapper.Map(entity); - } - - public virtual async Task MoveAsync(string containerName, Guid id, FileMoveRequestDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container, write: true); - - File entity = await FileRepository.GetAsync(id); - - await CheckFileIsInContainerAsync(container, entity); - - entity = await FileManager.ChangeNameAsync(container, entity, entity.FileName, input.TargetId); - - await FileInfoCheckProvider.CheckAsync(container, entity); - - await FileRepository.UpdateAsync(entity); - - return ObjectMapper.Map(entity); - } - - public virtual async Task UpdateAsync(string containerName, Guid id, FileUpdateDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container); - - File entity = await FileRepository.GetAsync(id); - - if (!entity.IsDirectory) - { - await CheckFileIsInContainerAsync(container, entity); - } - - entity = await FileManager.ChangeNameAsync(container, entity, input.FileName, entity.ParentId); - - await FileInfoCheckProvider.CheckAsync(container, entity); - - input.MapExtraPropertiesTo(entity); - - await FileRepository.UpdateAsync(entity); - - return ObjectMapper.Map(entity); - } - - public virtual async Task CreateDirectoryAsync(string containerName, FileDirectoryCreateDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container, write: true); - - File entity = await FileManager.CreateDirectoryAsync(container, input.FileName, input.ParentId); - - input.MapExtraPropertiesTo(entity); - - bool exists = await FileManager.IsDirectoryExistsAsync(container, entity); - if (!exists) - { - await FileRepository.InsertAsync(entity); - - return ObjectMapper.Map(entity); - } - - if (exists && !input.Force) - { - throw new BusinessException(FileManagementErrorCodes.DirectoryExists).WithData("name", entity.FileName); - } - - entity = await FileRepository.GetByNameAsync(container.Id, input.FileName, input.ParentId); - - return ObjectMapper.Map(entity); - } - - protected virtual async Task CreateFileAsync(FileContainer container, string fileName, Guid? parentId, string? mimeType, byte[] fileBytes, ExtensibleObject extensibleObject) - { - mimeType ??= FileMimeTypeProvider.Get(fileName); - - File entity = await FileManager.CreateFileAsync(container, fileName, mimeType, fileBytes, parentId); - - extensibleObject.MapExtraPropertiesTo(entity); - - await FileInfoCheckProvider.CheckAsync(container, entity); - - bool isExists = await FileManager.IsFileExistsAsync(container, entity); - - if (isExists && container.OverrideBehavior == FileOverrideBehavior.Override) - { - entity = await FileManager.FindFileAsync(container, entity.FileName, entity.ParentId); - - if (entity == null) - { - throw new EntityNotFoundException(); - } - - // update - entity = await FileManager.UpdateFileAsync(container, entity, fileBytes); - - await FileRepository.UpdateAsync(entity); - } - else if (isExists && container.OverrideBehavior == FileOverrideBehavior.Rename) - { - string newFileName = await FileRenameProvider.GetAsync(container, entity.FileName, entity.ParentId); - - entity.SetFileName(newFileName); - - // new - await FileRepository.InsertAsync(entity); - } - else - { - // new - await FileRepository.InsertAsync(entity); - } - - // save to blob - await FileManager.SaveBlobAsync(container, entity, fileBytes); - - return entity; - } - - /// - /// Check current identity can access this container - /// - /// - /// - protected override async Task CanAccessContainerAsync(FileContainer container, bool write = false) - { - bool isGranted = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Default); - - if (isGranted) - { - return true; - } - - if (container.AccessMode == FileAccessMode.Anonymous) - { - return true; - } - else if (container.AccessMode == FileAccessMode.Readonly && !write) - { - return true; - } - else if (container.AccessMode == FileAccessMode.Authorized && CurrentUser.IsAuthenticated) - { - return true; - } - else - { - // private & owner - return container.CreatorId == CurrentUser.Id; - } - } - - protected virtual async Task CheckContainerPermissionAsync(string containerName, string? policyName = null, bool write = false) - { - await CheckContainerPermissionAsync(FileContainerRepository, containerName, policyName, write); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileContainerAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileContainerAppService.cs deleted file mode 100644 index be913d1..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileContainerAppService.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Options; -using Passingwind.Abp.FileManagement.Options; -using Passingwind.Abp.FileManagement.Permissions; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Domain.Entities; -using Volo.Abp.ObjectExtending; - -namespace Passingwind.Abp.FileManagement.Files; - -[Authorize] -public class FileContainerAppService : FileManagementAppService, IFileContainerAppService -{ - protected FileManagementOptions FileManagementOptions { get; } - protected FileContainerManager FileContainerManager { get; } - protected IFileContainerRepository FileContainerRepository { get; } - protected IFileRepository FileRepository { get; } - protected IFileManager FileManager { get; } - - public FileContainerAppService( - IOptions fileManagementOptions, - FileContainerManager fileContainerManager, - IFileContainerRepository fileContainerRepository, - IFileRepository fileRepository, - IFileManager fileManager) - { - FileManagementOptions = fileManagementOptions.Value; - FileContainerManager = fileContainerManager; - FileContainerRepository = fileContainerRepository; - FileRepository = fileRepository; - FileManager = fileManager; - } - - public virtual async Task> GetAllListAsync() - { - // permission: anyone that get permission can list all or list owners. - - bool isManager = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Default); - - Guid? userId = isManager ? null : CurrentUser.Id; - - List list = await FileContainerRepository.GetListAsync(userId: userId); - - return new ListResultDto(ObjectMapper.Map, List>(list)); - } - - public virtual async Task> GetListAsync(FileContainerListRequestDto input) - { - // permission: anyone that get permission can list all or list owners. - - bool isManager = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Default); - - Guid? userId = isManager ? null : CurrentUser.Id; - - long count = await FileContainerRepository.GetCountAsync(input.Filter, userId: userId); - List list = await FileContainerRepository.GetPagedListAsync(input.SkipCount, input.MaxResultCount, input.Filter, userId, nameof(FileContainer.Name)); - - return new PagedResultDto() - { - Items = ObjectMapper.Map, List>(list), - TotalCount = count, - }; - } - - public virtual async Task GetAsync(Guid id) - { - // permission: anyone that get permission or owner can read. - - bool isManager = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Default); - - FileContainer entity = await FileContainerRepository.GetAsync(id); - - return !isManager && CurrentUser.Id != entity.CreatorId - ? throw new EntityNotFoundException() - : ObjectMapper.Map(entity); - } - - [AllowAnonymous] - public virtual async Task GetByNameAsync(string name) - { - // permission: anyone can query container name. - - bool isManager = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Default); - - FileContainer entity = await FileContainerRepository.GetAsync(x => x.Name == name); - - return !isManager && CurrentUser.Id != entity.CreatorId - ? throw new EntityNotFoundException() - : ObjectMapper.Map(entity); - } - - public virtual async Task CreateAsync(FileContainerCreateDto input) - { - // permission: anyone that authorized can create. - - FileContainer entity = await FileContainerManager.CreateAsync( - input.Name, - input.AccessMode, - input.Description, - input.MaximumEachFileSize, - input.MaximumFileQuantity, - input.OverrideBehavior, - input.AllowAnyFileExtension, - input.AllowedFileExtensions, - input.ProhibitedFileExtensions, - input.AutoDeleteBlob); - - input.MapExtraPropertiesTo(entity); - - if (await FileContainerManager.IsExistsAsync(entity)) - { - throw new BusinessException(FileManagementErrorCodes.ContainerExist).WithData("name", entity.Name); - } - - _ = await FileContainerRepository.InsertAsync(entity); - - return ObjectMapper.Map(entity); - } - - public virtual async Task UpdateAsync(Guid id, FileContainerUpdateDto input) - { - // permission: anyone that get permission or owners can update. - - bool isManager = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Update); - - FileContainer entity = await FileContainerRepository.GetAsync(id); - - if (!isManager && CurrentUser.Id != entity.CreatorId) - { - throw new EntityNotFoundException(); - } - - entity.Description = input.Description; - entity.MaximumEachFileSize = input.MaximumEachFileSize ?? 0; - entity.MaximumFileQuantity = input.MaximumFileQuantity ?? 0; - entity.OverrideBehavior = input.OverrideBehavior ?? FileOverrideBehavior.None; - entity.AllowAnyFileExtension = input.AllowAnyFileExtension ?? false; - entity.AllowedFileExtensions = input.AllowedFileExtensions; - entity.ProhibitedFileExtensions = input.ProhibitedFileExtensions; - entity.AutoDeleteBlob = input.AutoDeleteBlob; - - entity.SetAccessMode(input.AccessMode ?? FileManagementOptions.DefaultContainerAccessMode); - - input.MapExtraPropertiesTo(entity); - - _ = await FileContainerRepository.UpdateAsync(entity); - - return ObjectMapper.Map(entity); - } - - public virtual async Task DeleteAsync(Guid id) - { - // permission: anyone that get permission or owners can delete. - - bool isManager = await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileContainer.Delete); - - FileContainer entity = await FileContainerRepository.GetAsync(id); - - if (!isManager && CurrentUser.Id != entity.CreatorId) - { - return; - } - - long fileCount = await FileRepository.GetCountAsync(containerId: id); - - if (fileCount > 0 && !FileManagementOptions.AllowForceDeleteContainer) - { - throw new BusinessException(FileManagementErrorCodes.ContainerNotAllowForceDelete); - } - - // 1. delete file - await FileManager.ClearContainerFilesAsync(entity); - - // 2. delete container - await FileContainerRepository.DeleteAsync(id); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileShareAppService.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileShareAppService.cs deleted file mode 100644 index 08159ac..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Application/Files/FileShareAppService.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Options; -using Passingwind.Abp.FileManagement.Options; -using Volo.Abp; -using Volo.Abp.Content; - -namespace Passingwind.Abp.FileManagement.Files; - -[Authorize] -public class FileShareAppService : FileManagementAppService, IFileShareAppService -{ - protected IFileManager FileManager { get; } - protected IFileRepository FileRepository { get; } - protected IFileContainerRepository FileContainerRepository { get; } - protected IFileAccessTokenProvider FileAccessTokenProvider { get; } - protected FileManagementOptions FileManagementOptions { get; } - - public FileShareAppService( - IFileManager fileManager, - IFileRepository fileRepository, - IFileContainerRepository fileContainerRepository, - IFileAccessTokenProvider fileAccessTokenProvider, - IOptions options) - { - FileManager = fileManager; - FileRepository = fileRepository; - FileContainerRepository = fileContainerRepository; - FileAccessTokenProvider = fileAccessTokenProvider; - FileManagementOptions = options.Value; - } - - public virtual async Task CreateAsync(string containerName, Guid id, FileShareCreateRequestDto input) - { - FileContainer container = await FileContainerRepository.GetByNameAsync(containerName); - - await CheckContainerPermissionAsync(container); - - File entity = await FileRepository.GetAsync(id); - - await CheckFileIsInContainerAsync(container, entity); - - TimeSpan? expiration = input.ExpirationSecond.HasValue ? TimeSpan.FromSeconds(input.ExpirationSecond.Value) : null; - string token = await FileAccessTokenProvider.CreateAsync(container, entity, expiration); - - return new FileShareResultDto - { - FileName = entity.FileName, - Length = entity.Length, - MimeType = entity.MimeType, - ExpirationTime = expiration.HasValue ? Clock.Now.Add(expiration.Value) : null, - DownloadUrl = string.Format(FileManagementOptions.FileShareDownloadUrlFormat, token, container.Name), - Token = token, - }; - } - - [AllowAnonymous] - public virtual async Task GetAsync(string token) - { - FileAccessValidationResult validationResult = await FileAccessTokenProvider.ValidAsync(token); - - if (!validationResult.IsValid || validationResult.File == null) - { - throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); - } - - File file = validationResult.File; - - FileContainer container = await FileContainerRepository.FindAsync(file.ContainerId); - - return container == null - ? throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired) - : new FileShareResultDto - { - FileName = file.FileName, - Length = file.Length, - MimeType = file.MimeType, - ExpirationTime = validationResult.ExpirationTime, - DownloadUrl = string.Format(FileManagementOptions.FileShareDownloadUrlFormat, token), - Token = token, - }; - } - - [AllowAnonymous] - public virtual async Task GetBlobAsync(string token) - { - FileAccessValidationResult validationResult = await FileAccessTokenProvider.ValidAsync(token); - - if (!validationResult.IsValid || validationResult.File == null) - { - throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); - } - - File file = validationResult.File; - - FileContainer container = await FileContainerRepository.FindAsync(file.ContainerId); - - if (container == null) - { - throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); - } - - Stream? fileStream = await FileManager.GetFileSteamAsync(container, file); - - return fileStream == null ? throw new BlobNotFoundException() : (IRemoteStreamContent)new RemoteStreamContent(fileStream, file.FileName, file.MimeType); - } - - [AllowAnonymous] - public virtual async Task GetBytesAsync(string token) - { - FileAccessValidationResult validationResult = await FileAccessTokenProvider.ValidAsync(token); - - if (!validationResult.IsValid || validationResult.File == null) - { - throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); - } - - File file = validationResult.File; - - FileContainer container = await FileContainerRepository.FindAsync(file.ContainerId); - - return container == null - ? throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired) - : await FileManager.GetFileBytesAsync(container, file); - } - - [AllowAnonymous] - public virtual async Task GetStreamAsync(string token) - { - FileAccessValidationResult validationResult = await FileAccessTokenProvider.ValidAsync(token); - - if (!validationResult.IsValid || validationResult.File == null) - { - throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired); - } - - File file = validationResult.File; - - FileContainer container = await FileContainerRepository.FindAsync(file.ContainerId); - - return container == null - ? throw new BusinessException(FileManagementErrorCodes.ShareFileNotExistsOrExpired) - : await FileManager.GetFileSteamAsync(container, file); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/FileManagementConsts.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/FileManagementConsts.cs index de8f1f3..e858774 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/FileManagementConsts.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/FileManagementConsts.cs @@ -12,4 +12,6 @@ public static class FileManagementConsts public static int MaxFileItemUniqueIdLength { get; set; } = 32; public static int MaxFileAccessTokenTokenLength { get; set; } = 256; + + public static int MaxFileTagValueLength { get; set; } = 64; } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Files/FileAccessMode.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Files/FileAccessMode.cs index 4b22655..874929e 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Files/FileAccessMode.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Files/FileAccessMode.cs @@ -3,19 +3,24 @@ public enum FileAccessMode { /// - /// Anonymous can read & upload + /// Anonymous can read & write /// Anonymous = 0, /// - /// Anonymous can read + /// Anonymous can read, authorized user can write /// - Readonly = 1, + AnonymousReadonly = 1, /// - /// Only authorized user can read & upload + /// Only authorized user can read & write /// Authorized = 10, /// - /// Only created user can read & upload + /// control by /// Private = 20, + + ///// + ///// Readonly + ///// + //Readonly = 30, } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/en.json b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/en.json index 710e04d..cd99840 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/en.json +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/en.json @@ -1,5 +1,5 @@ { - "culture": "en", + "culture": "en", "texts": { "FileManagement:Error:ContainerExist": "The container '{name}' already exists", "FileManagement:Error:ContainerFileQuantitiesMaximumSurpass": "Too many file in container", @@ -14,6 +14,8 @@ "Permission:FileManagement": "File management", "Permission:FileManagement.FileContainer": "File containers", "Permission:FileManagement.File": "Files", + "Permission:FileManagement.File.Upload": "Upload", + "Permission:FileManagement.File.Download": "Download", "Permission:Create": "Create", "Permission:Update": "Edit", "Permission:Delete": "Delete" diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/zh-Hans.json b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/zh-Hans.json index 882fd89..a6c66f9 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/zh-Hans.json +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain.Shared/Localization/FileManagement/zh-Hans.json @@ -13,7 +13,9 @@ "Permission:FileManagement": "文件管理", "Permission:FileManagement.FileContainer": "文件容器", - "Permission:FileManagement.File": "文件", + "Permission:FileManagement.File": "文件", + "Permission:FileManagement.File.Upload": "上传", + "Permission:FileManagement.File.Download": "下载", "Permission:Create": "创建", "Permission:Update": "编辑", "Permission:Delete": "删除" diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/BackgroundWorkers/FileShareTokenCleanupBackgroundWorker.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/BackgroundWorkers/FileShareTokenCleanupBackgroundWorker.cs index fed50ac..cfdf184 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/BackgroundWorkers/FileShareTokenCleanupBackgroundWorker.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/BackgroundWorkers/FileShareTokenCleanupBackgroundWorker.cs @@ -1,7 +1,6 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Passingwind.Abp.FileManagement.Files; +using System.Threading.Tasks; using Volo.Abp.BackgroundWorkers; using Volo.Abp.DependencyInjection; using Volo.Abp.Threading; diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileAccessTokenProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileAccessTokenProvider.cs new file mode 100644 index 0000000..1a5a90b --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileAccessTokenProvider.cs @@ -0,0 +1,70 @@ +using Microsoft.Extensions.Caching.Distributed; +using System; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.Timing; + +namespace Passingwind.Abp.FileManagement; + +public class DefaultFileAccessTokenProvider : IFileAccessTokenProvider, ITransientDependency +{ + protected IClock Clock { get; } + protected IGuidGenerator GuidGenerator { get; } + protected IFileRepository FileRepository { get; } + protected IDistributedCache DistributedCache { get; } + protected IFileAccessTokenRepository FileAccessTokenRepository { get; } + + public DefaultFileAccessTokenProvider( + IClock clock, + IFileRepository fileRepository, + IDistributedCache distributedCache, + IFileAccessTokenRepository fileAccessTokenRepository, + IGuidGenerator guidGenerator) + { + Clock = clock; + FileRepository = fileRepository; + DistributedCache = distributedCache; + FileAccessTokenRepository = fileAccessTokenRepository; + GuidGenerator = guidGenerator; + } + + protected virtual Task GenerateTokenAsync(FileContainer container, FileItem file, CancellationToken cancellationToken = default) + { + var token = Guid.NewGuid().ToString("N"); + return Task.FromResult(token); + } + + public virtual async Task VerifyAsync(string token, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(token)) + { + throw new ArgumentException($"'{nameof(token)}' cannot be null or whitespace.", nameof(token)); + } + + var fileCacheItem = await DistributedCache.GetOrAddAsync(token, async () => + { + var entity = await FileAccessTokenRepository.FindAsync(x => x.Token == token, cancellationToken: cancellationToken); + return entity != null + ? new FileAccessTokenCacheItem(entity.Id, entity.FileId, entity.ExpirationTime ?? DateTime.MaxValue) + : FileAccessTokenCacheItem.Null(); + }, () => new DistributedCacheEntryOptions() + { + AbsoluteExpiration = Clock.Now.AddDays(1), + }, hideErrors: true, token: cancellationToken); + + if (fileCacheItem != null && fileCacheItem.ExpirationTime > Clock.Now) + { + var file = await FileRepository.FindAsync(fileCacheItem.FileId, cancellationToken: cancellationToken); + + if (file != null) + { + return FileAccessValidationResult.Valid(fileCacheItem.TokenId, file, fileCacheItem.ExpirationTime); + } + } + + return new FileAccessValidationResult(); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileBlobContainerProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileBlobContainerProvider.cs similarity index 67% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileBlobContainerProvider.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileBlobContainerProvider.cs index c9171d0..ff9b845 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileBlobContainerProvider.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileBlobContainerProvider.cs @@ -1,11 +1,11 @@ -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Options; using Passingwind.Abp.FileManagement.Options; +using System.Threading; +using System.Threading.Tasks; using Volo.Abp.BlobStoring; using Volo.Abp.DependencyInjection; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public class DefaultFileBlobContainerProvider : IFileBlobContainerProvider, ITransientDependency { @@ -20,13 +20,9 @@ public DefaultFileBlobContainerProvider(IBlobContainerFactory blobContainerFacto public virtual Task GetAsync(FileContainer container, CancellationToken cancellationToken = default) { - IBlobContainer blobContainer; - - if (_options.FileContainerAsBlobContainer) - blobContainer = _blobContainerFactor.Create(container.Name); - else - blobContainer = _blobContainerFactor.Create(_options.DefaultBlobContainer); - + var blobContainer = _options.FileContainerAsBlobContainer + ? _blobContainerFactor.Create(container.Name) + : _blobContainerFactor.Create(_options.DefaultBlobContainer); return Task.FromResult(blobContainer); } } \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileBlobNameGenerator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileBlobNameGenerator.cs similarity index 71% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileBlobNameGenerator.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileBlobNameGenerator.cs index 141bf80..3888f37 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileBlobNameGenerator.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileBlobNameGenerator.cs @@ -1,12 +1,12 @@ -using System; +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement.Options; +using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using Passingwind.Abp.FileManagement.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Timing; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public class DefaultFileBlobNameGenerator : IFileBlobNameGenerator, ITransientDependency { @@ -19,12 +19,12 @@ public DefaultFileBlobNameGenerator(IClock clock, IOptions CreateAsync(Guid containerId, Guid fileId, string uniqueId, string fileName, string mimeType, long length, string hash, CancellationToken cancellationToken = default) + public virtual Task CreateAsync(Guid containerId, Guid fileId, string uniqueId, string fileName, string? mimeType = null, long? length = null, string? hash = null, CancellationToken cancellationToken = default) { var now = _clock.Now; var directorySeparator = _options.BlobDirectorySeparator; - var blobName = $"{now.Year}{directorySeparator}{now.Month}{directorySeparator}{now.Day}{directorySeparator}{uniqueId}"; + var blobName = $"{now.Year}{directorySeparator}{now.Month}{directorySeparator}{now.Day}{directorySeparator}{fileId:N}"; return Task.FromResult(blobName); } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileHashCalculator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileHashCalculator.cs similarity index 86% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileHashCalculator.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileHashCalculator.cs index bc1cd09..b6e5479 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileHashCalculator.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileHashCalculator.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public class DefaultFileHashCalculator : IFileHashCalculator { @@ -17,7 +17,7 @@ public virtual Task GetAsync(byte[] bytes, CancellationToken cancellatio protected virtual IEnumerable GetMd5(byte[] fileContent) { - using MD5 md5 = MD5.Create(); + using var md5 = MD5.Create(); return md5.ComputeHash(fileContent); } } \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileRenameProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileRenameProvider.cs new file mode 100644 index 0000000..7d1c01b --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileRenameProvider.cs @@ -0,0 +1,75 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; + +namespace Passingwind.Abp.FileManagement; + +public class DefaultFileRenameProvider : IFileRenameProvider, ITransientDependency +{ + protected IFileRepository FileRepository { get; } + protected IFileContainerRepository FileContainerRepository { get; } + protected IFileMimeTypeProvider FileMimeTypeProvider { get; } + + public DefaultFileRenameProvider(IFileRepository fileRepository, IFileContainerRepository fileContainerRepository, IFileMimeTypeProvider fileMimeTypeProvider) + { + FileRepository = fileRepository; + FileContainerRepository = fileContainerRepository; + FileMimeTypeProvider = fileMimeTypeProvider; + } + + public virtual async Task RenameAsync(string container, string fileName, Guid? parentId = null, bool isDirectory = false, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return await RenameAsync(fileContainer, fileName, parentId, isDirectory, cancellationToken); + } + + public virtual async Task RenameAsync(FileContainer container, string fileName, Guid? parentId = null, bool isDirectory = false, CancellationToken cancellationToken = default) + { + if (container is null) + { + throw new ArgumentNullException(nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var name = Path.GetFileNameWithoutExtension(fileName); + var ext = Path.GetExtension(fileName); + var mimeType = FileMimeTypeProvider.Get(fileName); + + if (parentId == null) + { + parentId = Guid.Empty; + } + + bool fileExists = false; + + do + { + fileExists = await FileRepository.IsFileNameExistsAsync(containerId: container.Id, fileName: fileName, parentId: parentId, isDirectory: false, cancellationToken: cancellationToken); + + if (!fileExists) + { + break; + } + + name = $"{name} - renamed"; + + var count = await FileRepository.CountAsync(x => x.ContainerId == container.Id + && x.IsDirectory == isDirectory + && x.ParentId == parentId + && x.MimeType == mimeType + && x.FileName.StartsWith(name), cancellationToken: cancellationToken); + + fileName = $"{name} ({count + 1}){ext}"; + } while (fileExists); + + return fileName; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileUniqueIdGenerator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileUniqueIdGenerator.cs similarity index 52% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileUniqueIdGenerator.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileUniqueIdGenerator.cs index 2cfb5d9..4272f0a 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileUniqueIdGenerator.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/DefaultFileUniqueIdGenerator.cs @@ -3,13 +3,12 @@ using System.Threading.Tasks; using Volo.Abp.DependencyInjection; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public class DefaultFileUniqueIdGenerator : IFileUniqueIdGenerator, ISingletonDependency { - public virtual Task CreateAsync(FileContainer fileContainer, Guid fileId, CancellationToken cancellationToken = default) + public virtual Task CreateAsync(Guid containerId, Guid fileId, string fileName, bool isDirectory, CancellationToken cancellationToken = default) { - // return Nanoid.Nanoid.GenerateAsync(size: 32); return Task.FromResult(fileId.ToString("N")); } } \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/EventHandler/FileEventHander.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/EventHandler/FileEventHander.cs index 12b2bdd..2db0db8 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/EventHandler/FileEventHander.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/EventHandler/FileEventHander.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events; using Volo.Abp.EventBus; @@ -8,8 +7,8 @@ namespace Passingwind.Abp.FileManagement.EventHandler; public class FileEventHander : - ILocalEventHandler>, - ILocalEventHandler>, + ILocalEventHandler>, + ILocalEventHandler>, ITransientDependency { private readonly IFileContainerRepository _fileContainerRepository; @@ -20,30 +19,38 @@ public FileEventHander(IFileContainerRepository fileContainerRepository) } [UnitOfWork] - public virtual async Task HandleEventAsync(EntityCreatedEventData eventData) + public virtual async Task HandleEventAsync(EntityCreatedEventData eventData) { var entity = eventData.Entity; if (entity.IsDirectory) + { return; + } var container = await _fileContainerRepository.FindAsync(entity.ContainerId); if (container != null) + { await _fileContainerRepository.IncrementFileCountAsync(container.Name, 1); + } } [UnitOfWork] - public virtual async Task HandleEventAsync(EntityDeletedEventData eventData) + public virtual async Task HandleEventAsync(EntityDeletedEventData eventData) { var entity = eventData.Entity; if (entity.IsDirectory) + { return; + } var container = await _fileContainerRepository.FindAsync(entity.ContainerId); if (container?.FilesCount > 0) + { await _fileContainerRepository.IncrementFileCountAsync(container.Name, -1); + } } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessToken.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessToken.cs new file mode 100644 index 0000000..37ce624 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessToken.cs @@ -0,0 +1,42 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Passingwind.Abp.FileManagement; + +public class FileAccessToken : CreationAuditedAggregateRoot, IMultiTenant +{ + protected FileAccessToken() + { + } + + public FileAccessToken(Guid id, Guid containerId, Guid fileId, string fileName, long length, string? mimeType, string token, DateTime? expirationTime, Guid? tenantId = null) : base(id) + { + ContainerId = containerId; + FileId = fileId; + FileName = fileName; + Length = length; + MimeType = mimeType; + Token = token; + ExpirationTime = expirationTime; + TenantId = tenantId; + } + + public Guid ContainerId { get; protected set; } + public Guid FileId { get; protected set; } + public string FileName { get; protected set; } = null!; + public long Length { get; protected set; } + public string? MimeType { get; protected set; } + + public string Token { get; protected set; } = null!; + public DateTime? ExpirationTime { get; protected set; } + + public uint DownloadCount { get; protected set; } + + public Guid? TenantId { get; protected set; } + + public void SetDownloadCount(uint value) + { + DownloadCount = value; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessTokenCacheItem.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessTokenCacheItem.cs similarity index 63% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessTokenCacheItem.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessTokenCacheItem.cs index bb915bf..a33c542 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessTokenCacheItem.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessTokenCacheItem.cs @@ -1,17 +1,19 @@ using System; using Volo.Abp.Caching; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; [CacheName("filemanagement:file:accesstoken")] public class FileAccessTokenCacheItem { + public Guid TokenId { get; protected set; } public Guid FileId { get; protected set; } - public DateTime? ExpirationTime { get; protected set; } + public DateTime ExpirationTime { get; protected set; } - public FileAccessTokenCacheItem(Guid fileId, DateTime? expirationTime) + public FileAccessTokenCacheItem(Guid tokenId, Guid fileId, DateTime expirationTime) { + TokenId = tokenId; FileId = fileId; ExpirationTime = expirationTime; } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessTokenManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessTokenManager.cs similarity index 84% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessTokenManager.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessTokenManager.cs index a1608ed..1436c02 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessTokenManager.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessTokenManager.cs @@ -3,7 +3,7 @@ using Volo.Abp.Domain.Services; using Volo.Abp.Uow; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public class FileAccessTokenManager : DomainService { @@ -19,6 +19,6 @@ public virtual async Task DeleteAllExpirationTokenAsync(CancellationToken cancel { var endTime = Clock.Now; - await _fileAccessTokenRepository.DeleteDirectAsync(x => x.ExpirationTime < endTime, cancellationToken); + await _fileAccessTokenRepository.DeleteDirectAsync(x => x.ExpirationTime != null && x.ExpirationTime < endTime, cancellationToken); } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessValidationResult.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessValidationResult.cs similarity index 60% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessValidationResult.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessValidationResult.cs index 6f94acb..57c7222 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessValidationResult.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileAccessValidationResult.cs @@ -1,22 +1,24 @@ using System; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public class FileAccessValidationResult { + public Guid TokenId { get; protected set; } public bool IsValid { get; protected set; } public DateTime? ExpirationTime { get; protected set; } - public File? File { get; protected set; } + public FileItem? File { get; protected set; } public FileAccessValidationResult() { IsValid = false; } - public static FileAccessValidationResult Valid(File file, DateTime? ExpirationTime) + public static FileAccessValidationResult Valid(Guid tokenId, FileItem file, DateTime? ExpirationTime) { return new FileAccessValidationResult { + TokenId = tokenId, IsValid = true, File = file, ExpirationTime = ExpirationTime, diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileContainer.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainer.cs similarity index 84% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileContainer.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainer.cs index b44ef95..44f95a8 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileContainer.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainer.cs @@ -1,10 +1,13 @@ using System; +using System.Collections.Generic; +using Passingwind.Abp.FileManagement.Files; +using Volo.Abp.Auditing; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; -public class FileContainer : FullAuditedAggregateRoot, IMultiTenant +public class FileContainer : FullAuditedAggregateRoot, IMultiTenant, IHasEntityVersion { public virtual Guid? TenantId { get; protected set; } @@ -18,7 +21,7 @@ public class FileContainer : FullAuditedAggregateRoot, IMultiTenant public virtual string? Description { get; set; } /// - /// maximun length for single file + /// maximun length for single file (KB) /// public virtual long MaximumEachFileSize { get; set; } = long.MaxValue; @@ -42,6 +45,10 @@ public class FileContainer : FullAuditedAggregateRoot, IMultiTenant public virtual int FilesCount { get; protected set; } + public int EntityVersion { get; protected set; } + + public List Accesses { get; set; } = []; + protected FileContainer() { } @@ -52,11 +59,6 @@ public FileContainer(Guid id, string name, FileAccessMode accessMode) : base(id) AccessMode = accessMode; } - public void SetName(string name) - { - Name = name; - } - public void SetAccessMode(FileAccessMode accessMode) { AccessMode = accessMode; diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccess.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccess.cs new file mode 100644 index 0000000..eeb617e --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccess.cs @@ -0,0 +1,20 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; + +namespace Passingwind.Abp.FileManagement; + +public class FileContainerAccess : AuditedEntity +{ + public Guid FileContainerId { get; set; } + public string ProviderName { get; set; } = null!; + public string ProviderKey { get; set; } = null!; + + public bool Read { get; set; } + public bool Write { get; set; } + public bool Delete { get; set; } + + public override object[] GetKeys() + { + return [FileContainerId, ProviderName, ProviderKey]; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccessProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccessProvider.cs new file mode 100644 index 0000000..b4e3df1 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerAccessProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Passingwind.Abp.FileManagement; + +public class FileContainerAccessProvider : IFileContainerAccessProvider, ITransientDependency +{ + public Task IsGrantedAsync(string name, string providerName, Guid providerId, CancellationToken cancellationToken = default) + { + return Task.FromResult(true); + } + + public Task IsGrantedAsync(Guid containerId, string providerName, Guid providerId, CancellationToken cancellationToken = default) + { + return Task.FromResult(true); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerManager.cs new file mode 100644 index 0000000..95719d2 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileContainerManager.cs @@ -0,0 +1,80 @@ +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement.Files; +using Passingwind.Abp.FileManagement.Options; +using System; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; + +namespace Passingwind.Abp.FileManagement; + +public class FileContainerManager : DomainService, IFileContainerManager +{ + protected IFileContainerRepository FileContainerRepository { get; } + protected FileManagementOptions FileManagementOptions { get; } + protected IFileContainerAccessProvider FileContainerAccessProvider { get; } + + public FileContainerManager(IFileContainerRepository fileContainerRepository, IOptions options, IFileContainerAccessProvider fileContainerAccessProvider) + { + FileContainerRepository = fileContainerRepository; + FileManagementOptions = options.Value; + FileContainerAccessProvider = fileContainerAccessProvider; + } + + public virtual async Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default) + { + return await FileContainerRepository.GetAsync(id, cancellationToken: cancellationToken); + } + + public virtual async Task GetByNameAsync(string name, CancellationToken cancellationToken = default) + { + return await FileContainerRepository.GetByNameAsync(name, cancellationToken); + } + + public virtual async Task IsExistsAsync(FileContainer fileContainer, CancellationToken cancellationToken = default) + { + return await FileContainerRepository.IsNameExistsAsync(fileContainer.Name, new[] { fileContainer.Id }, cancellationToken); + } + + public virtual async Task IsExistsAsync(string name, CancellationToken cancellationToken = default) + { + return await FileContainerRepository.IsNameExistsAsync(name, cancellationToken: cancellationToken); + } + + public virtual async Task CheckExistsAsync(string name, CancellationToken cancellationToken = default) + { + _ = await FileContainerRepository.GetByNameAsync(name, cancellationToken); + } + + public virtual async Task CreateAsync(string name, FileAccessMode accessMode = FileAccessMode.Authorized, FileOverrideBehavior overrideBehavior = FileOverrideBehavior.None, string? description = null, long? maximumEachFileSize = null, int? maximumFileQuantity = null, bool? allowAnyFileExtension = null, string? allowedFileExtensions = null, string? prohibitedFileExtensions = null, bool? autoDeleteBlob = false) + { + var entity = new FileContainer(GuidGenerator.Create(), name, accessMode) + { + Description = description, + MaximumEachFileSize = maximumEachFileSize ?? FileManagementOptions.DefaultMaximumFileSize, + MaximumFileQuantity = maximumFileQuantity ?? FileManagementOptions.DefaultContainerMaximumFileQuantity, + AllowAnyFileExtension = allowAnyFileExtension ?? false, + AllowedFileExtensions = allowedFileExtensions ?? string.Join(",", FileManagementOptions.DefaultAllowedFileExtensions ?? new string[0]), + ProhibitedFileExtensions = prohibitedFileExtensions ?? string.Join(",", FileManagementOptions.DefaultProhibitedFileExtensions ?? new string[0]), + OverrideBehavior = overrideBehavior, + AutoDeleteBlob = autoDeleteBlob ?? false, + }; + + return await FileContainerRepository.InsertAsync(entity); + } + + public virtual async Task UpdateAsync(FileContainer fileContainer, CancellationToken cancellationToken = default) + { + return await FileContainerRepository.UpdateAsync(fileContainer, cancellationToken: cancellationToken); + } + + public virtual async Task DeleteAsync(FileContainer fileContainer, CancellationToken cancellationToken = default) + { + await FileContainerRepository.DeleteAsync(fileContainer, cancellationToken: cancellationToken); + } + + public virtual async Task CanAccessAsync(string name, string providerName, Guid providerId, CancellationToken cancellationToken = default) + { + return await FileContainerAccessProvider.IsGrantedAsync(name, providerName, providerId, cancellationToken); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileInfoCheckProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileInfoCheckProvider.cs new file mode 100644 index 0000000..6b0319b --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileInfoCheckProvider.cs @@ -0,0 +1,90 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp; + +namespace Passingwind.Abp.FileManagement; + +public class FileInfoCheckProvider : IFileInfoCheckProvider +{ + private readonly IFileRepository _fileRepository; + private readonly IFileContainerRepository _fileContainerRepository; + + public FileInfoCheckProvider(IFileRepository fileRepository, IFileContainerRepository fileContainerRepository) + { + _fileRepository = fileRepository; + _fileContainerRepository = fileContainerRepository; + } + + public virtual async Task CheckAsync(FileContainer container, string fileName, string mimeType, long length, CancellationToken cancellationToken = default) + { + // check file extensions + if (await CheckFileExtensionAsync(container, fileName, cancellationToken)) + { + throw new BusinessException(FileManagementErrorCodes.FileExtensionNotAllowed).WithData("ext", Path.GetExtension(fileName)); + } + + // check file extensions + if (await CheckFileSizeAsync(container, length, cancellationToken)) + { + throw new BusinessException(FileManagementErrorCodes.FileLengthTooLarge).WithData("size", length); + } + + // check container file quantity + if (await CheckContainerFileTotalQuantitiesAsync(container, cancellationToken)) + { + throw new BusinessException(FileManagementErrorCodes.ContainerFileQuantitiesMaximumSurpass); + } + } + + public virtual async Task IsValidAsync(FileContainer container, string fileName, string mimeType, long length, CancellationToken cancellationToken = default) + { + // check file extensions + if (await CheckFileExtensionAsync(container, fileName, cancellationToken)) + { + return false; + } + + // check file extensions + if (await CheckFileSizeAsync(container, length, cancellationToken)) + { + return false; + } + + // check container file quantity + return !await CheckContainerFileTotalQuantitiesAsync(container, cancellationToken); + } + + protected virtual Task CheckFileExtensionAsync(FileContainer container, string fileName, CancellationToken cancellationToken = default) + { + // check file extensions + var fileExtension = Path.GetExtension(fileName); + + if (container.AllowAnyFileExtension && container.GetProhibitedFileExtensions()?.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase) == true) + { + return Task.FromResult(true); + } + else + { + return !container.AllowAnyFileExtension && container.GetAllowedFileExtensions()?.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase) != true + ? Task.FromResult(true) + : Task.FromResult(false); + } + } + + protected virtual Task CheckFileSizeAsync(FileContainer container, long length, CancellationToken cancellationToken = default) + { + // check size + return container.MaximumEachFileSize < length ? Task.FromResult(true) : Task.FromResult(false); + } + + protected virtual async Task CheckContainerFileTotalQuantitiesAsync(FileContainer container, CancellationToken cancellationToken = default) + { + // check container file quantity + var filesCount = await _fileRepository.GetCountAsync(containerId: container.Id, isDirectory: false, cancellationToken: cancellationToken); + + return container.MaximumFileQuantity <= filesCount; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/File.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItem.cs similarity index 51% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/File.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItem.cs index 394b8c9..4d3cdfc 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/File.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItem.cs @@ -1,10 +1,12 @@ using System; +using System.Collections.Generic; +using Volo.Abp.Auditing; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; -public class File : FullAuditedAggregateRoot, IMultiTenant +public class FileItem : FullAuditedAggregateRoot, IMultiTenant, IHasEntityVersion { public virtual Guid? TenantId { get; protected set; } @@ -21,7 +23,7 @@ public class File : FullAuditedAggregateRoot, IMultiTenant /// public virtual string UniqueId { get; protected set; } = null!; - public virtual string? MimeType { get; protected set; } + public virtual string? MimeType { get; set; } public virtual long Length { get; protected set; } @@ -29,37 +31,55 @@ public class File : FullAuditedAggregateRoot, IMultiTenant public virtual string? Hash { get; protected set; } - protected File() + public int EntityVersion { get; protected set; } + + public virtual List Tags { get; protected set; } = []; + + protected FileItem() { } - public File( + public FileItem( Guid id, Guid containerId, bool isDirectory, string fileName, string blobName, + Guid? parentId = null, string? mimeType = null, long? length = null, string? hash = null, - string? uniqueId = null) : base(id) + string? uniqueId = null, + Guid? tenantId = null) : base(id) { ContainerId = containerId; IsDirectory = isDirectory; FileName = fileName; + ParentId = parentId ?? Guid.Empty; MimeType = mimeType; Length = length ?? 0; BlobName = blobName; Hash = hash; - UniqueId = uniqueId ?? id.ToString("N").Substring(8, 16); // TODO + UniqueId = uniqueId ?? id.ToString("N"); + TenantId = tenantId; } public void SetFileName(string fileName) { - if (fileName == null) - throw new ArgumentNullException(nameof(fileName)); + if (FileName == fileName) + { + return; + } - FileName = fileName; + var oldName = FileName; + FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); + + AddDistributedEvent(new FileNameChangedEvent(Id, ContainerId, ParentId, IsDirectory, UniqueId, fileName, oldName, TenantId)); + } + + public void ChangeContainerId(Guid value) + { + ContainerId = value; } public void ChangeParentId(Guid parentId) @@ -67,12 +87,12 @@ public void ChangeParentId(Guid parentId) ParentId = parentId; } - public void UpdateMimeType(string mimeType) + public void SetMimeType(string mimeType) { MimeType = mimeType; } - public void UpdateLength(long length) + public void SetLength(long length) { Length = length; } @@ -81,4 +101,17 @@ public void SetUniqueId(string uniqueId) { UniqueId = uniqueId; } + + public void SetHash(string hash) + { + Hash = hash; + } + + public void AddTags(params string[] tags) + { + foreach (var tag in tags) + { + Tags.AddIfNotContains(x => x.Tags == tag, () => new FileTags() { Tags = tag }); + } + } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAccess.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAccess.cs new file mode 100644 index 0000000..3560985 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAccess.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Passingwind.Abp.FileManagement; + +public class FileItemAccess : AuditedEntity, IMultiTenant +{ + public Guid FileId { get; set; } + public Guid? TenantId { get; } + public string ProviderName { get; set; } = null!; + public Guid ProviderId { get; set; } + public bool Read { get; set; } + public bool Write { get; set; } + public bool Delete { get; set; } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAlreadyExistsException.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAlreadyExistsException.cs new file mode 100644 index 0000000..f3f5cd6 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileItemAlreadyExistsException.cs @@ -0,0 +1,18 @@ +using System; + +namespace Passingwind.Abp.FileManagement; + +public class FileItemAlreadyExistsException : Exception +{ + public FileItemAlreadyExistsException() + { + } + + public FileItemAlreadyExistsException(string message) : base(message) + { + } + + public FileItemAlreadyExistsException(string message, Exception innerException) : base(message, innerException) + { + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagementDomainModule.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagementDomainModule.cs index c088b05..dd0095d 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagementDomainModule.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagementDomainModule.cs @@ -1,8 +1,7 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Passingwind.Abp.FileManagement.BackgroundWorkers; -using Passingwind.Abp.FileManagement.Files; using Passingwind.Abp.FileManagement.Options; +using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.BackgroundWorkers; using Volo.Abp.BlobStoring; @@ -21,8 +20,6 @@ public class FileManagementDomainModule : AbpModule public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddOptions("FileManagement"); - - context.Services.AddTransient(); } public override async Task OnPostApplicationInitializationAsync(ApplicationInitializationContext context) diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManager.cs new file mode 100644 index 0000000..0a04288 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManager.cs @@ -0,0 +1,1067 @@ +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement.Files; +using Passingwind.Abp.FileManagement.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.BlobStoring; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Services; + +namespace Passingwind.Abp.FileManagement; + +public class FileManager : DomainService, IFileManager +{ + protected IBlobContainerFactory BlobContainerFactor { get; } + protected IFileAccessTokenRepository FileAccessTokenRepository { get; } + protected IFileBlobContainerProvider FileBlobContainerProvider { get; } + protected IFileBlobNameGenerator FileBlobNameGenerator { get; } + protected IFileContainerRepository FileContainerRepository { get; } + protected IFileHashCalculator FileHashCalculator { get; } + protected IFileInfoCheckProvider FileInfoCheckProvider { get; } + protected FileManagementOptions FileManagementOptions { get; } + protected IFileMimeTypeProvider FileMimeTypeProvider { get; } + protected IFileRenameProvider FileRenameProvider { get; } + protected IFileRepository FileRepository { get; } + protected IFileUniqueIdGenerator FileUniqueIdGenerator { get; } + + public FileManager( + IOptions fileManagementOptions, + IFileRepository fileRepository, + IFileContainerRepository fileContainerRepository, + IBlobContainerFactory blobContainerFactor, + IFileBlobNameGenerator fileBlobNameGenerator, + IFileHashCalculator fileHashCalculator, + IFileMimeTypeProvider fileMimeTypeProvider, + IFileUniqueIdGenerator fileUniqueIdGenerator, + IFileBlobContainerProvider fileBlobContainerProvider, + IFileInfoCheckProvider fileInfoCheckProvider, + IFileRenameProvider fileRenameProvider, + IFileAccessTokenRepository fileAccessTokenRepository) + { + FileManagementOptions = fileManagementOptions.Value; + FileRepository = fileRepository; + FileContainerRepository = fileContainerRepository; + BlobContainerFactor = blobContainerFactor; + FileBlobNameGenerator = fileBlobNameGenerator; + FileHashCalculator = fileHashCalculator; + FileMimeTypeProvider = fileMimeTypeProvider; + FileUniqueIdGenerator = fileUniqueIdGenerator; + FileBlobContainerProvider = fileBlobContainerProvider; + FileInfoCheckProvider = fileInfoCheckProvider; + FileRenameProvider = fileRenameProvider; + FileAccessTokenRepository = fileAccessTokenRepository; + } + + public virtual async Task ChangeFileNameAsync(Guid containerId, string fileName, string newFileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + if (string.IsNullOrEmpty(newFileName)) + { + throw new ArgumentException($"'{nameof(newFileName)}' cannot be null or empty.", nameof(newFileName)); + } + + if (fileName == newFileName) + { + throw new ArgumentException("The new file name can't be same as origin name"); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + return await ChangeFileNameAsync(fileContainer, fileName, newFileName, parentId, cancellationToken); + } + + public virtual async Task ChangeFileNameAsync(string container, string fileName, string newFileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + if (string.IsNullOrEmpty(newFileName)) + { + throw new ArgumentException($"'{nameof(newFileName)}' cannot be null or empty.", nameof(newFileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return await ChangeFileNameAsync(fileContainer, fileName, newFileName, parentId, cancellationToken); + } + + public virtual async Task CheckAsync(string container, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + if (string.IsNullOrWhiteSpace(mimeType)) + { + mimeType = FileMimeTypeProvider.Get(Path.GetExtension(fileName)); + } + + await FileInfoCheckProvider.CheckAsync(fileContainer, fileName, mimeType!, length, cancellationToken: cancellationToken); + } + + public virtual async Task CheckAsync(Guid containerId, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + if (string.IsNullOrWhiteSpace(mimeType)) + { + mimeType = FileMimeTypeProvider.Get(Path.GetExtension(fileName)); + } + + await FileInfoCheckProvider.CheckAsync(fileContainer, fileName, mimeType!, length, cancellationToken: cancellationToken); + } + + public virtual async Task ClearContainerFilesAsync(Guid containerId, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + await ClearContainerFilesAsync(fileContainer, cancellationToken); + } + + public virtual async Task ClearContainerFilesAsync(string container, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + await ClearContainerFilesAsync(fileContainer, cancellationToken); + } + + public virtual Task CopyDirectoryAsync(Guid containerId, Guid fileId, string targetFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual Task CopyDirectoryAsync(string container, Guid fileId, string targetFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual async Task CopyFileAsync(Guid containerId, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + var stream = await GetFileSteamAsync(containerId, fileId, cancellationToken: cancellationToken) ?? throw new UserFriendlyException("The source file blob is not found."); + await SaveAsync(containerId, fileName: file.FileName, stream: stream, parentId: targetParentId, overrideExisting: overrideExisting, cancellationToken: cancellationToken); + } + + public virtual async Task CopyFileAsync(string container, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(targetFileName)) + { + throw new ArgumentException($"'{nameof(targetFileName)}' cannot be null or empty.", nameof(targetFileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + await CopyFileAsync(containerId: fileContainer.Id, fileId: fileId, targetFileName: targetFileName, targetParentId: targetParentId, overrideExisting: overrideExisting, cancellationToken: cancellationToken); + } + + public virtual async Task CreateAccessTokenAsync(Guid containerId, Guid fileId, TimeSpan? expiration = null, CancellationToken cancellationToken = default) + { + var token = await GenerateTokenAsync(containerId, fileId, cancellationToken); + + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + + if (file?.IsDirectory != false) + { + throw new EntityNotFoundException(typeof(FileItem)); + } + + DateTime? expirationTime = expiration.HasValue ? Clock.Now.Add(expiration.Value) : null; + var entity = new FileAccessToken(GuidGenerator.Create(), containerId, fileId, file.FileName, file.Length, file.MimeType, token, expirationTime); + + // add record to DB + return await FileAccessTokenRepository.InsertAsync(entity, cancellationToken: cancellationToken); + } + + public virtual async Task CreateArchiveAsync(Guid containerId, Guid fileId, string archiveFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(archiveFileName)) + { + throw new ArgumentException($"'{nameof(archiveFileName)}' cannot be null or empty.", nameof(archiveFileName)); + } + + if (!overrideExisting && await FileRepository.IsFileNameExistsAsync(containerId, archiveFileName, parentId: targetParentId, isDirectory: false, cancellationToken: cancellationToken)) + { + throw new FileItemAlreadyExistsException(); + } + + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + + var result = new MemoryStream(); + using var zip = new ZipArchive(result, ZipArchiveMode.Create, false); + + if (file.IsDirectory) + { + var files = await GetFilesAsync(containerId, fileId, includeSubDirectory, cancellationToken); + foreach (var item in files) + { + // TODO: directory name + var blobStream = await GetFileSteamAsync(containerId, item.Id, cancellationToken); + if (blobStream == null) + { + throw new BlobNotFoundException($"The file id {item.Id} blob not found."); + } + var entry = zip.CreateEntry(item.FileName); + await blobStream.CopyToAsync(entry.Open()); + } + } + else + { + var blobStream = await GetFileSteamAsync(containerId, file.Id, cancellationToken); + if (blobStream == null) + { + throw new BlobNotFoundException($"The file id {file.Id} blob not found."); + } + var entry = zip.CreateEntry(file.FileName); + await blobStream.CopyToAsync(entry.Open()); + } + + // + return await SaveAsync(containerId, archiveFileName, result, parentId: targetParentId, overrideExisting: overrideExisting, cancellationToken: cancellationToken); + } + + public virtual async Task CreateArchiveAsync(string container, Guid fileId, string archiveFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(archiveFileName)) + { + throw new ArgumentException($"'{nameof(archiveFileName)}' cannot be null or empty.", nameof(archiveFileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return await CreateArchiveAsync(fileContainer.Id, fileId, archiveFileName, includeSubDirectory, targetParentId, overrideExisting, cancellationToken); + } + + public virtual async Task CreateDirectoryAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return await CreateDirectoryAsync(fileContainer, fileName, parentId, cancellationToken); + } + + public virtual async Task CreateDirectoryAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + return await CreateDirectoryAsync(fileContainer, fileName, parentId, cancellationToken); + } + + public virtual async Task DeleteAsync(string container, string fileName, Guid? parentId = null, bool forceDelete = false, CancellationToken cancellationToken = default) + { + var file = await FindAsync(container, fileName, parentId, cancellationToken); + + return file != null && await DeleteAsync(container, file.Id, forceDelete, cancellationToken); + } + + public virtual async Task DeleteAsync(string container, Guid fileId, bool forceDelete = false, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return await DeleteAsync(fileContainer.Id, fileId, forceDelete, cancellationToken); + } + + public virtual async Task DeleteAsync(Guid containerId, Guid fileId, bool forceDelete = false, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken: cancellationToken); + + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + + if (file == null) + { + return false; + } + + if (file.IsDirectory && forceDelete) + { + // TODO + } + + if (fileContainer.AutoDeleteBlob && !file.IsDirectory) + { + await blobContainer.DeleteAsync(file.BlobName, cancellationToken); + } + + // record + await FileRepository.DeleteAsync(file, cancellationToken: cancellationToken); + + return true; + } + + public virtual async Task FindAccessTokenAsync(Guid tokenId, CancellationToken cancellationToken = default) + { + return await FileAccessTokenRepository.FindAsync(tokenId, cancellationToken: cancellationToken); + } + + public virtual async Task FindAsync(Guid fileId, CancellationToken cancellationToken = default) + { + return await FileRepository.FindAsync(fileId, cancellationToken: cancellationToken); + } + + public virtual async Task FindAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.FindByNameAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, cancellationToken: cancellationToken); + } + + public virtual async Task FindAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.FindByNameAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, cancellationToken: cancellationToken); + } + + public virtual async Task FindDirectoryAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.FindByNameAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, isDirectory: true, cancellationToken: cancellationToken); + } + + public virtual async Task FindDirectoryAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.FindByNameAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, isDirectory: true, cancellationToken: cancellationToken); + } + + public virtual async Task FindFileAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.FindByNameAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, isDirectory: false, cancellationToken: cancellationToken); + } + + public virtual async Task FindFileAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.FindByNameAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, isDirectory: false, cancellationToken: cancellationToken); + } + + public virtual Task GenerateTokenAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default) + { + return Task.FromResult(Guid.NewGuid().ToString("N")); + } + + public virtual async Task GetAsync(Guid fileId, CancellationToken cancellationToken = default) + { + return await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + } + + public async Task GetAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return await GetAsync(fileContainer.Id, fileName, parentId, cancellationToken); + } + + public async Task GetAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + return await FileRepository.GetByNameAsync(containerId, fileName, parentId, cancellationToken: cancellationToken); + } + + public Task GetDirectoryAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public Task GetDirectoryAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public Task GetFileAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public Task GetFileAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual async Task GetFileBytesAsync(string container, Guid fileId, CancellationToken cancellationToken = default) + { + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken); + + return await blobContainer.GetAllBytesOrNullAsync(file.BlobName, cancellationToken); + } + + public virtual async Task GetFileBytesAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default) + { + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken); + + return await blobContainer.GetAllBytesOrNullAsync(file.BlobName, cancellationToken); + } + + public virtual async Task GetFileBytesAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + var file = await FindFileAsync(container, fileName, parentId, cancellationToken); + + if (file == null) + { + return null; + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken); + + return await blobContainer.GetAllBytesOrNullAsync(file.BlobName, cancellationToken); + } + + public virtual async Task GetFileCountAsync(string container, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return fileContainer.FilesCount; + } + + public virtual async Task GetFileSteamAsync(string container, Guid fileId, CancellationToken cancellationToken = default) + { + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken); + + return await blobContainer.GetOrNullAsync(file.BlobName, cancellationToken); + } + + public virtual async Task GetFileSteamAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default) + { + var file = await FileRepository.GetAsync(fileId, cancellationToken: cancellationToken); + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken); + + return await blobContainer.GetOrNullAsync(file.BlobName, cancellationToken); + } + + public virtual async Task GetFileSteamAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + var file = await FindFileAsync(container, fileName, parentId, cancellationToken); + + if (file == null) + { + return null; + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken); + + return await blobContainer.GetOrNullAsync(file.BlobName, cancellationToken); + } + + public virtual async Task> GetTagsAsync(Guid fileId, CancellationToken cancellationToken = default) + { + var entity = await FindAsync(fileId, cancellationToken); + + return entity == null ? throw new EntityNotFoundException(typeof(FileItem)) : (IReadOnlyList)entity.Tags; + } + + public virtual async Task> GetTagsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + var entity = await FindAsync(container, fileName, parentId, cancellationToken); + + return entity == null ? throw new EntityNotFoundException(typeof(FileItem)) : entity.Tags.ConvertAll(x => x.Tags); + } + + public virtual async Task> GetTagsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + var entity = await FindAsync(containerId, fileName, parentId, cancellationToken); + + return entity == null ? throw new EntityNotFoundException(typeof(FileItem)) : entity.Tags.ConvertAll(x => x.Tags); + } + + public Task> GetTagsAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual async Task IsDirectoryExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + _ = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.IsFileNameExistsAsync(containerId, fileName: fileName, parentId: parentId, isDirectory: true, cancellationToken: cancellationToken); + } + + public virtual async Task IsDirectoryExistsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.IsFileNameExistsAsync(fileContainer.Id, fileName: fileName, parentId: parentId, isDirectory: true, cancellationToken: cancellationToken); + } + + public virtual async Task IsExistsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.IsFileNameExistsAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, cancellationToken: cancellationToken); + } + + public virtual async Task IsExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.IsFileNameExistsAsync(containerId: fileContainer.Id, fileName: fileName, parentId: parentId, cancellationToken: cancellationToken); + } + + public virtual async Task IsFileExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.IsFileNameExistsAsync(fileContainer.Id, fileName: fileName, parentId: parentId, isDirectory: false, cancellationToken: cancellationToken); + } + + public virtual async Task IsFileExistsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + parentId ??= Guid.Empty; + + return await FileRepository.IsFileNameExistsAsync(fileContainer.Id, fileName: fileName, parentId: parentId, isDirectory: false, cancellationToken: cancellationToken); + } + public virtual Task IsReadOnlyAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual Task IsReadOnlyAsync(Guid fileId, bool isReadOnly, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public Task IsReadOnlyAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public Task IsReadOnlyAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual async Task IsValidAsync(string container, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + if (string.IsNullOrWhiteSpace(mimeType)) + { + mimeType = FileMimeTypeProvider.Get(Path.GetExtension(fileName)); + } + + return await FileInfoCheckProvider.IsValidAsync(fileContainer, fileName, mimeType!, length, cancellationToken: cancellationToken); + } + + public virtual async Task IsValidAsync(Guid containerId, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default) + { + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + if (string.IsNullOrWhiteSpace(mimeType)) + { + mimeType = FileMimeTypeProvider.Get(Path.GetExtension(fileName)); + } + + return await FileInfoCheckProvider.IsValidAsync(fileContainer, fileName, mimeType!, length, cancellationToken: cancellationToken); + } + + public virtual async Task SaveAsync(string container, string fileName, Stream stream, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.Seek(0, SeekOrigin.Begin); + + using var ms = new MemoryStream(); + await stream.CopyToAsync(ms); + + return await SaveAsync(container: container, fileName: fileName, bytes: ms.ToArray(), mimeType: mimeType, parentId: parentId, ignoreCheck: ignoreCheck, overrideExisting: overrideExisting, cancellationToken: cancellationToken); + } + + public virtual async Task SaveAsync(string container, string fileName, byte[] bytes, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(container)) + { + throw new ArgumentException($"'{nameof(container)}' cannot be null or empty.", nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + if (bytes is null) + { + throw new ArgumentNullException(nameof(bytes)); + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + return await SaveAsync(containerId: fileContainer.Id, fileName: fileName, bytes: bytes, mimeType: mimeType, parentId: parentId, ignoreCheck: ignoreCheck, cancellationToken: cancellationToken); + } + + public virtual async Task SaveAsync(Guid containerId, string fileName, Stream stream, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.Seek(0, SeekOrigin.Begin); + + using var ms = new MemoryStream(); + await stream.CopyToAsync(ms); + + return await SaveAsync(containerId: containerId, fileName: fileName, bytes: ms.ToArray(), mimeType: mimeType, parentId: parentId, ignoreCheck: ignoreCheck, overrideExisting: overrideExisting, cancellationToken: cancellationToken); + } + + public virtual async Task SaveAsync(Guid containerId, string fileName, byte[] bytes, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + if (bytes is null) + { + throw new ArgumentNullException(nameof(bytes)); + } + + var fileContainer = await FileContainerRepository.GetAsync(containerId, cancellationToken: cancellationToken); + + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken); + + if (parentId == null) + { + parentId = Guid.Empty; + } + + var fileExists = await FileRepository.IsFileNameExistsAsync( + containerId: fileContainer.Id, + fileName: fileName, + parentId: parentId, + isDirectory: false, + cancellationToken: cancellationToken); + + if (fileContainer.OverrideBehavior == FileOverrideBehavior.Override) + { + overrideExisting = true; + } + else if (fileContainer.OverrideBehavior == FileOverrideBehavior.Rename) + { + fileName = await FileRenameProvider.RenameAsync(fileContainer, fileName, parentId, isDirectory: false, cancellationToken: cancellationToken); + fileExists = false; + } + + if (!overrideExisting && fileExists && fileContainer.OverrideBehavior == FileOverrideBehavior.None) + { + throw new BusinessException(FileManagementErrorCodes.FileExists); + } + + var length = bytes.Length < 1024 ? 1 : bytes.Length / 1024; // KB + var hash = await FileHashCalculator.GetAsync(bytes, cancellationToken); + + FileItem entity; + if (fileExists) + { + entity = await FileRepository.GetByNameAsync(fileContainer.Id, fileName, parentId, false, cancellationToken); + entity.SetLength(length); + entity.SetHash(hash); + } + else + { + var fileId = GuidGenerator.Create(); + var uniqueId = await FileUniqueIdGenerator.CreateAsync(fileContainer.Id, fileId, fileName, true, cancellationToken); + var blobName = await FileBlobNameGenerator.CreateAsync(fileContainer.Id, fileId, uniqueId, fileName, cancellationToken: cancellationToken); + + if (string.IsNullOrWhiteSpace(mimeType)) + { + mimeType = FileMimeTypeProvider.Get(Path.GetExtension(fileName)); + } + + if (!ignoreCheck) + { + await FileInfoCheckProvider.CheckAsync(fileContainer, fileName, mimeType!, length, cancellationToken: cancellationToken); + } + + entity = new FileItem( + fileId, + fileContainer.Id, + isDirectory: false, + fileName: fileName, + blobName: blobName, + parentId: parentId ?? Guid.Empty, + mimeType: mimeType, + length: length, + hash: hash, + uniqueId: uniqueId, + tenantId: CurrentTenant.Id); + + await FileRepository.InsertAsync(entity, cancellationToken: cancellationToken); + } + + // save blob + await blobContainer.SaveAsync(entity.BlobName, bytes, true, cancellationToken: cancellationToken); + + return entity; + } + + public virtual Task SetReadOnlyAsync(Guid fileId, bool isReadOnly, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public Task SetReadOnlyAsync(Guid containerId, Guid fileId, bool isReadOnly, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual async Task SetTagsAsync(Guid fileId, IEnumerable tags, CancellationToken cancellationToken = default) + { + if (tags == null) + { + throw new ArgumentNullException(nameof(tags)); + } + + var entity = await FindAsync(fileId, cancellationToken); + + if (entity == null) + { + throw new EntityNotFoundException(typeof(FileItem)); + } + + entity.AddTags(tags.ToArray()); + } + + public virtual async Task SetTagsAsync(Guid containerId, Guid fileId, IEnumerable tags, CancellationToken cancellationToken = default) + { + if (tags == null) + { + throw new ArgumentNullException(nameof(tags)); + } + + var entity = await FindAsync(fileId, cancellationToken); + + if (entity == null) + { + throw new EntityNotFoundException(typeof(FileItem)); + } + + entity.AddTags(tags.ToArray()); + } + + public virtual Task UnarchiveAsync(Guid containerId, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public virtual Task UnarchiveAsync(string container, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + protected virtual async Task ChangeFileNameAsync(FileContainer container, string fileName, string newFileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (container is null) + { + throw new ArgumentNullException(nameof(container)); + } + + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + if (string.IsNullOrEmpty(newFileName)) + { + throw new ArgumentException($"'{nameof(newFileName)}' cannot be null or empty.", nameof(newFileName)); + } + + if (fileName == newFileName) + { + throw new ArgumentException("The new file name can't be same as origin name"); + } + + var file = await FindAsync(container.Id, fileName, parentId, cancellationToken); + + if (file == null) + { + throw new EntityNotFoundException(typeof(FileItem)); + } + + var name = await FileRenameProvider.RenameAsync(container, newFileName, parentId, cancellationToken: cancellationToken); + + file.SetFileName(name); + + await FileRepository.UpdateAsync(file, cancellationToken: cancellationToken); + + return file; + } + + protected virtual async Task ClearContainerFilesAsync(FileContainer fileContainer, CancellationToken cancellationToken = default) + { + var blobContainer = await FileBlobContainerProvider.GetAsync(fileContainer, cancellationToken: cancellationToken); + + // blob + if (fileContainer.AutoDeleteBlob) + { + var files = await FileRepository.GetListAsync(containerId: fileContainer.Id, cancellationToken: cancellationToken); + foreach (var file in files) + { + if (!file.IsDirectory) + { + await blobContainer.DeleteAsync(file.BlobName, cancellationToken); + } + } + } + + // record + await FileRepository.DeleteDirectAsync(x => x.ContainerId == fileContainer.Id, cancellationToken); + } + + protected async Task CreateDirectoryAsync(FileContainer container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(fileName)) + { + throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); + } + + var fileId = GuidGenerator.Create(); + var uniqueId = await FileUniqueIdGenerator.CreateAsync(container.Id, fileId, fileName, true, cancellationToken); + var blobName = await FileBlobNameGenerator.CreateAsync(container.Id, fileId, uniqueId, fileName, cancellationToken: cancellationToken); + + var entity = new FileItem( + fileId, + container.Id, + isDirectory: true, + fileName: fileName, + blobName: blobName, + parentId: parentId ?? Guid.Empty, + uniqueId: uniqueId, + tenantId: CurrentTenant.Id); + + return await FileRepository.InsertAsync(entity, cancellationToken: cancellationToken); + } + + public async Task> GetFilesAsync(string container, string directoryName, Guid? parentId = null, bool includeSubDirectory = false, CancellationToken cancellationToken = default) + { + if (parentId == null) + { + parentId = Guid.Empty; + } + + var fileContainer = await FileContainerRepository.GetByNameAsync(container, cancellationToken); + + var directory = await FileRepository.GetAsync(x => x.FileName == directoryName && x.IsDirectory && x.ParentId == parentId, cancellationToken: cancellationToken); + + return await GetFilesAsync(fileContainer.Id, directory.Id, includeSubDirectory, cancellationToken); + } + + public async Task> GetFilesAsync(Guid containerId, string directoryName, Guid? parentId = null, bool includeSubDirectory = false, CancellationToken cancellationToken = default) + { + if (parentId == null) + { + parentId = Guid.Empty; + } + + var directory = await FileRepository.GetAsync(x => x.FileName == directoryName && x.IsDirectory && x.ParentId == parentId, cancellationToken: cancellationToken); + + return await GetFilesAsync(containerId, directory.Id, includeSubDirectory, cancellationToken); + } + + public async Task> GetFilesAsync(Guid containerId, Guid directoryId, bool includeSubDirectory = false, CancellationToken cancellationToken = default) + { + var list = await FileRepository.GetListAsync(containerId: containerId, parentId: directoryId, cancellationToken: cancellationToken); + + if (includeSubDirectory) + { + foreach (var item in list) + { + list.AddRange(await GetFilesAsync(containerId: containerId, directoryId: item.Id, includeSubDirectory: true, cancellationToken: cancellationToken)); + } + } + + return list; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagerExtensions.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagerExtensions.cs new file mode 100644 index 0000000..31d8481 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileManagerExtensions.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Passingwind.Abp.FileManagement; + +public static class FileManagerExtensions +{ + public static async Task EnsureDirectoryExistsAsync(this IFileManager fileManager, string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (!await fileManager.IsDirectoryExistsAsync(container, fileName, parentId, cancellationToken: cancellationToken)) + { + await fileManager.CreateDirectoryAsync(container, fileName, parentId, cancellationToken: cancellationToken); + } + } + + public static async Task EnsureDirectoryExistsAsync(this IFileManager fileManager, Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + { + if (!await fileManager.IsDirectoryExistsAsync(containerId, fileName, parentId, cancellationToken: cancellationToken)) + { + await fileManager.CreateDirectoryAsync(containerId, fileName, parentId, cancellationToken: cancellationToken); + } + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileMimeTypeProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileMimeTypeProvider.cs new file mode 100644 index 0000000..297a043 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileMimeTypeProvider.cs @@ -0,0 +1,15 @@ +using HeyRed.Mime; +using System; +using System.IO; + +namespace Passingwind.Abp.FileManagement; + +public class FileMimeTypeProvider : IFileMimeTypeProvider +{ + public string Get(string fileName) + { + return string.IsNullOrWhiteSpace(fileName) + ? throw new ArgumentException($"'{nameof(fileName)}' cannot be null or whitespace.", nameof(fileName)) + : MimeTypesMap.GetMimeType(Path.GetExtension(fileName)); + } +} \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileNameChangedEvent.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileNameChangedEvent.cs new file mode 100644 index 0000000..1ac1fc1 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileNameChangedEvent.cs @@ -0,0 +1,31 @@ +using System; + +namespace Passingwind.Abp.FileManagement; + +public class FileNameChangedEvent +{ + public FileNameChangedEvent(Guid id, Guid containerId, Guid parentId, bool isDirectory, string uniqueId, string fileName, string oldFileName, Guid? tenantId) + { + Id = id; + ContainerId = containerId; + ParentId = parentId; + IsDirectory = isDirectory; + UniqueId = uniqueId; + FileName = fileName; + OldFileName = oldFileName; + TenantId = tenantId; + } + + public Guid Id { get; } + + public virtual Guid ContainerId { get; } + + public virtual Guid ParentId { get; } + + public virtual bool IsDirectory { get; } + + public virtual string UniqueId { get; } = null!; + public virtual string FileName { get; } = null!; + public virtual string OldFileName { get; } = null!; + public virtual Guid? TenantId { get; } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileTags.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileTags.cs new file mode 100644 index 0000000..07d2d8b --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/FileTags.cs @@ -0,0 +1,15 @@ +using System; +using Volo.Abp.Domain.Entities; + +namespace Passingwind.Abp.FileManagement; + +public class FileTags : Entity +{ + public Guid FileId { get; set; } + public string Tags { get; set; } = null!; + + public override object[] GetKeys() + { + return [FileId, Tags]; + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileAccessTokenProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileAccessTokenProvider.cs deleted file mode 100644 index d9e0028..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileAccessTokenProvider.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Guids; -using Volo.Abp.Timing; - -namespace Passingwind.Abp.FileManagement.Files; - -public class DefaultFileAccessTokenProvider : IFileAccessTokenProvider, ITransientDependency -{ - protected IClock Clock { get; } - protected IGuidGenerator GuidGenerator { get; } - protected IFileRepository FileRepository { get; } - protected IDistributedCache DistributedCache { get; } - protected IFileAccessTokenRepository FileAccessTokenRepository { get; } - - public DefaultFileAccessTokenProvider( - IClock clock, - IFileRepository fileRepository, - IDistributedCache distributedCache, - IFileAccessTokenRepository fileAccessTokenRepository, - IGuidGenerator guidGenerator) - { - Clock = clock; - FileRepository = fileRepository; - DistributedCache = distributedCache; - FileAccessTokenRepository = fileAccessTokenRepository; - GuidGenerator = guidGenerator; - } - -#pragma warning disable RCS1163 // Unused parameter. - protected virtual Task GenerateTokenAsync(FileContainer container, File file, CancellationToken cancellationToken = default) -#pragma warning restore RCS1163 // Unused parameter. - { - string token = Guid.NewGuid().ToString("N"); - return Task.FromResult(token); - } - - public virtual async Task CreateAsync(FileContainer container, File file, TimeSpan? expiration = null, CancellationToken cancellationToken = default) - { - string token = await GenerateTokenAsync(container, file, cancellationToken); - - DateTime? expirationTime = expiration.HasValue ? Clock.Now.Add(expiration.Value) : null; - - var checheItem = new FileAccessTokenCacheItem(file.Id, expirationTime); - var cacheOptions = new Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions() - { - AbsoluteExpiration = expirationTime, - }; - - // add to cache - await DistributedCache.SetAsync(token, checheItem, cacheOptions, token: cancellationToken); - - // add record to DB - await FileAccessTokenRepository.InsertAsync(new FileAccessToken(GuidGenerator.Create(), file.Id, token, expirationTime), cancellationToken: cancellationToken); - - return token; - } - - public virtual async Task ValidAsync(string token, CancellationToken cancellationToken = default) - { - // priority from cache - var fileCacheItem = await DistributedCache.GetAsync(token); - - // if cache lost - if (fileCacheItem == null) - { - var entity = await FileAccessTokenRepository.FindAsync(x => x.Token == token); - if (entity != null) - { - fileCacheItem = new FileAccessTokenCacheItem(entity.FileId, entity.ExpirationTime); - var cacheOptions = new Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions() - { - AbsoluteExpiration = entity.ExpirationTime, - }; - - await DistributedCache.SetAsync(token, fileCacheItem, cacheOptions, token: cancellationToken); - } - else - { - var cacheOptions = new Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions() - { - AbsoluteExpiration = Clock.Now.AddDays(1), - }; - - // set 'null' cache - await DistributedCache.SetAsync(token, FileAccessTokenCacheItem.Null(), options: cacheOptions, token: cancellationToken); - } - } - - if (fileCacheItem != null && fileCacheItem.ExpirationTime > Clock.Now) - { - var file = await FileRepository.FindAsync(fileCacheItem.FileId); - - if (file != null) - { - return FileAccessValidationResult.Valid(file, fileCacheItem.ExpirationTime); - } - } - - return new FileAccessValidationResult(); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileRenameProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileRenameProvider.cs deleted file mode 100644 index 0ceb0c7..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/DefaultFileRenameProvider.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Repositories; - -namespace Passingwind.Abp.FileManagement.Files; - -public class DefaultFileRenameProvider : IFileRenameProvider, ITransientDependency -{ - private readonly IFileRepository _fileRepository; - - public DefaultFileRenameProvider(IFileRepository fileRepository) - { - _fileRepository = fileRepository; - } - - public virtual async Task GetAsync(FileContainer container, string fileName, Guid? parentId, CancellationToken cancellationToken = default) - { - // TODO - bool exist = false; - - var newFileName = fileName; - - var name = Path.GetFileNameWithoutExtension(fileName); - var ext = Path.GetExtension(newFileName); - - var count = await _fileRepository.CountAsync(x => x.ContainerId == container.Id && x.ParentId == parentId, cancellationToken); - - newFileName = $"{name} - renamed{count + 1}{ext}"; - - int loopIndex = 0; - - do - { - loopIndex++; - - exist = await _fileRepository.IsFileNameExistsAsync(container.Id, newFileName, parentId); - - if (exist) - { - newFileName = $"{name} - renamed{count + 1}_{loopIndex}{ext}"; - } - } while (exist); - - return newFileName; - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessToken.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessToken.cs deleted file mode 100644 index 00c1ea3..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileAccessToken.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using Volo.Abp.Domain.Entities.Auditing; - -namespace Passingwind.Abp.FileManagement.Files; - -public class FileAccessToken : CreationAuditedAggregateRoot -{ - protected FileAccessToken() - { - } - - public FileAccessToken(Guid id, Guid fileId, string token, DateTime? expirationTime = null) : base(id) - { - FileId = fileId; - Token = token; - ExpirationTime = expirationTime; - } - - public Guid FileId { get; protected set; } - - public string Token { get; protected set; } = null!; - - public DateTime? ExpirationTime { get; protected set; } - - public uint DownloadCount { get; protected set; } - - public void SetDownloadCount(uint value) - { - DownloadCount = value; - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileContainerManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileContainerManager.cs deleted file mode 100644 index 4be72f2..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileContainerManager.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using Passingwind.Abp.FileManagement.Options; -using Volo.Abp.Domain.Services; - -namespace Passingwind.Abp.FileManagement.Files; - -public class FileContainerManager : DomainService -{ - protected IFileContainerRepository FileContainerRepository { get; } - protected FileManagementOptions FileManagementOptions { get; } - - public FileContainerManager(IFileContainerRepository fileContainerRepository, IOptions options) - { - FileContainerRepository = fileContainerRepository; - FileManagementOptions = options.Value; - } - - public virtual async Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default) - { - return await FileContainerRepository.GetAsync(id, cancellationToken: cancellationToken); - } - - public virtual async Task GetByNameAsync(string name, CancellationToken cancellationToken = default) - { - return await FileContainerRepository.GetByNameAsync(name, cancellationToken); - } - - public virtual async Task IsExistsAsync(FileContainer fileContainer, CancellationToken cancellationToken = default) - { - return await FileContainerRepository.CheckExistsAsync(fileContainer, cancellationToken); - } - - public virtual async Task CheckExistsAsync(string name, CancellationToken cancellationToken = default) - { - _ = await FileContainerRepository.GetByNameAsync(name, cancellationToken); - } - - public virtual Task CreateAsync( - string name, - FileAccessMode? accessMode, - string? description = null, - long? maximumEachFileSize = null, - int? maximumFileQuantity = null, - FileOverrideBehavior? overrideBehavior = null, - bool? allowAnyFileExtension = null, - string? allowedFileExtensions = null, - string? prohibitedFileExtensions = null, - bool? autoDeleteBlob = false) - { - var entity = new FileContainer(GuidGenerator.Create(), name, accessMode ?? FileManagementOptions.DefaultContainerAccessMode) - { - Description = description, - MaximumEachFileSize = maximumEachFileSize ?? FileManagementOptions.DefaultMaximumFileSize, - MaximumFileQuantity = maximumFileQuantity ?? FileManagementOptions.DefaultContainerMaximumFileQuantity, - AllowAnyFileExtension = allowAnyFileExtension ?? false, - AllowedFileExtensions = allowedFileExtensions ?? string.Join(",", FileManagementOptions.DefaultAllowedFileExtensions ?? new string[0]), - ProhibitedFileExtensions = prohibitedFileExtensions ?? string.Join(",", FileManagementOptions.DefaultProhibitedFileExtensions ?? new string[0]), - OverrideBehavior = overrideBehavior ?? FileManagementOptions.DefaultOverrideBehavior, - AutoDeleteBlob = autoDeleteBlob ?? false, - }; - - return Task.FromResult(entity); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileHashDuplicateDetectionProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileHashDuplicateDetectionProvider.cs deleted file mode 100644 index c7f4e29..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileHashDuplicateDetectionProvider.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Passingwind.Abp.FileManagement.Files; - -//public class FileHashDuplicateDetectionProvider : IFileDuplicateDetectionProvider -//{ -// private readonly IFileRepository _fileRepository; - -// public FileHashDuplicateDetectionProvider(IFileRepository fileRepository) -// { -// _fileRepository = fileRepository; -// } - -// public virtual async Task IsExistsAsync(FileContainer fileContainer, File file, CancellationToken cancellationToken = default) -// { -// return await _fileRepository.AnyAsync(x => x.Id != file.Id -// && x.Hash == file.Hash -// && x.ParentId == file.ParentId -// && x.ContainerId == file.ContainerId -// && x.IsDirectory == file.IsDirectory, -// cancellationToken); -// } -//} \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileInfoCheckProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileInfoCheckProvider.cs deleted file mode 100644 index 6cb2c32..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileInfoCheckProvider.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp; - -namespace Passingwind.Abp.FileManagement.Files; - -public class FileInfoCheckProvider : IFileInfoCheckProvider -{ - private readonly IFileRepository _fileRepository; - private readonly IFileContainerRepository _fileContainerRepository; - private readonly IFileDuplicateDetectionProvider _fileDuplicateDetectionProvider; - - public FileInfoCheckProvider(IFileRepository fileRepository, IFileContainerRepository fileContainerRepository, IFileDuplicateDetectionProvider fileDuplicateDetectionProvider) - { - _fileRepository = fileRepository; - _fileContainerRepository = fileContainerRepository; - _fileDuplicateDetectionProvider = fileDuplicateDetectionProvider; - } - - public virtual async Task CheckAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (!file.IsDirectory) - { - // check file extensions - await CheckFileExtensionAsync(container, file, cancellationToken); - - // check file extensions - await CheckFileSizeAsync(container, file, cancellationToken); - - // check file exists - await CheckFileExistsAsync(container, file, cancellationToken); - - // check container file quantity - await CheckContainerFileTotalQuantitiesAsync(container, file, cancellationToken); - } - else - { - await CheckDirectoryExistsAsync(container, file, cancellationToken); - } - } - - protected virtual Task CheckFileExtensionAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (file.IsDirectory) - return Task.CompletedTask; - - // check file extensions - var fileExtension = Path.GetExtension(file.FileName); - - if (container.AllowAnyFileExtension && container.GetProhibitedFileExtensions()?.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase) == true) - { - throw new BusinessException(FileManagementErrorCodes.FileExtensionNotAllowed).WithData("ext", fileExtension); - } - - if (!container.AllowAnyFileExtension && container.GetAllowedFileExtensions()?.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase) != true) - { - throw new BusinessException(FileManagementErrorCodes.FileExtensionNotAllowed).WithData("ext", fileExtension); - } - - return Task.CompletedTask; - } - - protected virtual Task CheckFileSizeAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (file.IsDirectory) - return Task.CompletedTask; - - // check size - if (container.MaximumEachFileSize < file.Length) - { - throw new BusinessException(FileManagementErrorCodes.FileLengthTooLarge).WithData("size", file.Length); - } - - return Task.CompletedTask; - } - - protected virtual async Task CheckFileExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (file.IsDirectory) - return; - - if (container.OverrideBehavior != FileOverrideBehavior.None) - return; - - // check override - var exist = await IsFileExistsAsync(container, file, cancellationToken); - - if (exist) - { - throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", file.FileName); - } - } - - protected virtual async Task CheckDirectoryExistsAsync(FileContainer container, File entity, CancellationToken cancellationToken = default) - { - if (!entity.IsDirectory) - return; - - // check override - var exist = await IsDirectoryExistsAsync(container, entity, cancellationToken); - - if (exist) - { - throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", entity.FileName); - } - } - - protected virtual async Task CheckContainerFileTotalQuantitiesAsync(FileContainer container, File entity, CancellationToken cancellationToken = default) - { - var filesCount = await _fileRepository.GetCountAsync(containerId: container.Id, isDirectory: false); - - if (container.MaximumFileQuantity <= filesCount) - { - throw new BusinessException(FileManagementErrorCodes.ContainerFileQuantitiesMaximumSurpass).WithData("fileName", entity.FileName); - } - } - - protected async Task IsFileExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - return await _fileDuplicateDetectionProvider.IsExistsAsync(container, file, cancellationToken); - } - - protected async Task IsDirectoryExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - return await _fileDuplicateDetectionProvider.IsExistsAsync(container, file, cancellationToken); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileManager.cs deleted file mode 100644 index 75099d2..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileManager.cs +++ /dev/null @@ -1,453 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using Passingwind.Abp.FileManagement.Options; -using Volo.Abp; -using Volo.Abp.BlobStoring; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.Domain.Services; -using Volo.Abp.Uow; - -namespace Passingwind.Abp.FileManagement.Files; - -public class FileManager : DomainService, IFileManager -{ - private IFileRepository FileRepository { get; } - private IFileContainerRepository FileContainerRepository { get; } - private IBlobContainerFactory BlobContainerFactor { get; } - private IFileBlobNameGenerator FileBlobNameGenerator { get; } - private IFileHashCalculator FileHashCalculator { get; } - private IFileMimeTypeProvider FileMimeTypeProvider { get; } - private IFileUniqueIdGenerator FileUniqueIdGenerator { get; } - private IFileBlobContainerProvider FileBlobContainerProvider { get; } - private IFileDuplicateDetectionProvider FileDuplicateDetectionProvider { get; } - private FileManagementOptions FileManagementOptions { get; } - - public FileManager( - IFileRepository fileRepository, - IFileContainerRepository fileContainerRepository, - IBlobContainerFactory blobContainerFactor, - IFileBlobNameGenerator fileBlobNameGenerator, - IFileHashCalculator fileHashCalculator, - IFileMimeTypeProvider fileMimeTypeProvider, - IFileUniqueIdGenerator fileUniqueIdGenerator, - IFileBlobContainerProvider fileBlobContainerProvider, - IFileDuplicateDetectionProvider fileDuplicateDetectionProvider, - IOptions options) - { - FileRepository = fileRepository; - FileContainerRepository = fileContainerRepository; - BlobContainerFactor = blobContainerFactor; - FileBlobNameGenerator = fileBlobNameGenerator; - FileHashCalculator = fileHashCalculator; - FileMimeTypeProvider = fileMimeTypeProvider; - FileUniqueIdGenerator = fileUniqueIdGenerator; - FileBlobContainerProvider = fileBlobContainerProvider; - FileDuplicateDetectionProvider = fileDuplicateDetectionProvider; - FileManagementOptions = options.Value; - } - - public virtual async Task FindFileAsync(FileContainer container, string fileName, Guid? parentId, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (string.IsNullOrEmpty(fileName)) - { - throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); - } - - return await FileRepository.FirstOrDefaultAsync(x => x.FileName == fileName && x.ParentId == parentId && x.ContainerId == container.Id && !x.IsDirectory); - } - - public virtual async Task IsFileExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (file.IsDirectory) - throw new ArgumentException(); - - return await FileDuplicateDetectionProvider.IsExistsAsync(container, file, cancellationToken); - } - - public virtual async Task IsDirectoryExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (!file.IsDirectory) - throw new ArgumentException(); - - return await FileDuplicateDetectionProvider.IsExistsAsync(container, file, cancellationToken); - } - - public virtual Task CheckFileExtensionAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (file.IsDirectory) - return Task.CompletedTask; - - // check file extensions - var fileExtension = Path.GetExtension(file.FileName); - - if (container.AllowAnyFileExtension && container.GetProhibitedFileExtensions()?.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase) == true) - { - throw new BusinessException(FileManagementErrorCodes.FileExtensionNotAllowed).WithData("ext", fileExtension); - } - - if (!container.AllowAnyFileExtension && container.GetAllowedFileExtensions()?.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase) != true) - { - throw new BusinessException(FileManagementErrorCodes.FileExtensionNotAllowed).WithData("ext", fileExtension); - } - - return Task.CompletedTask; - } - - public virtual Task CheckFileSizeAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (file.IsDirectory) - return Task.CompletedTask; - - // check size - if (container.MaximumEachFileSize < file.Length) - { - throw new BusinessException(FileManagementErrorCodes.FileLengthTooLarge).WithData("size", file.Length); - } - - return Task.CompletedTask; - } - - public virtual async Task CheckFileExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (file.IsDirectory) - return; - - // check override - var exist = await IsFileExistsAsync(container, file, cancellationToken); - - if (exist) - { - throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", file.FileName); - } - } - - public virtual async Task CheckDirectoryExistsAsync(FileContainer container, File entity, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (entity is null) - { - throw new ArgumentNullException(nameof(entity)); - } - - if (!entity.IsDirectory) - return; - - // check override - var exist = await IsDirectoryExistsAsync(container, entity, cancellationToken); - - if (exist) - { - throw new BusinessException(FileManagementErrorCodes.FileExists).WithData("fileName", entity.FileName); - } - } - - public virtual async Task CreateFileAsync(FileContainer container, string fileName, string mimeType, byte[] bytes, Guid? parentId = null, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (string.IsNullOrEmpty(fileName)) - { - throw new ArgumentException($"'{nameof(fileName)}' cannot be null or empty.", nameof(fileName)); - } - - if (bytes is null) - { - throw new ArgumentNullException(nameof(bytes)); - } - - var hash = await FileHashCalculator.GetAsync(bytes); - - var fileId = GuidGenerator.Create(); - var uniqueId = await FileUniqueIdGenerator.CreateAsync(container, fileId); - var blobName = await FileBlobNameGenerator.CreateAsync(container.Id, fileId, uniqueId, fileName, mimeType, bytes.Length, hash); - - var file = new File( - fileId, - container.Id, - isDirectory: false, - fileName: fileName, - blobName: blobName, - mimeType: mimeType, - length: bytes.Length, - hash: hash, - uniqueId: uniqueId); - - file.ChangeParentId(parentId ?? Guid.Empty); - - return file; - } - - public virtual async Task CreateDirectoryAsync(FileContainer container, string name, Guid? parentId, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentException($"'{nameof(name)}' cannot be null or empty.", nameof(name)); - } - - var fileId = GuidGenerator.Create(); - var uniqueId = await FileUniqueIdGenerator.CreateAsync(container, fileId); - var blobName = await FileBlobNameGenerator.CreateAsync(container.Id, fileId, uniqueId, name, string.Empty, 0, string.Empty); - - var file = new File( - fileId, - container.Id, - isDirectory: true, - fileName: name, - blobName: blobName, - mimeType: null, - length: 0, - hash: null, - uniqueId: uniqueId); - - file.ChangeParentId(parentId ?? Guid.Empty); - - return file; - } - - public virtual Task UpdateFileAsync(FileContainer container, File file, byte[] bytes, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (bytes is null) - { - throw new ArgumentNullException(nameof(bytes)); - } - - file.UpdateLength(bytes.Length); - - return Task.FromResult(file); - } - - public virtual async Task GetFileBytesAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - var blobContainer = await FileBlobContainerProvider.GetAsync(container); - - return await blobContainer.GetAllBytesOrNullAsync(file.BlobName, cancellationToken); - } - - public virtual async Task GetFileSteamAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - var blobContainer = await FileBlobContainerProvider.GetAsync(container); - - return await blobContainer.GetOrNullAsync(file.BlobName, cancellationToken); - } - - public virtual async Task SaveBlobAsync(FileContainer container, File file, Stream stream, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - var blobContainer = await FileBlobContainerProvider.GetAsync(container); - - await blobContainer.SaveAsync(file.BlobName, stream, true, cancellationToken); - } - - public virtual async Task SaveBlobAsync(FileContainer container, File file, byte[] bytes, CancellationToken cancellationToken = default) - { - if (container is null) - { - throw new ArgumentNullException(nameof(container)); - } - - if (file is null) - { - throw new ArgumentNullException(nameof(file)); - } - - if (bytes is null) - { - throw new ArgumentNullException(nameof(bytes)); - } - - var blobContainer = await FileBlobContainerProvider.GetAsync(container); - - await blobContainer.SaveAsync(file.BlobName, bytes, true, cancellationToken); - } - - public virtual async Task ChangeNameAsync(FileContainer container, File file, string newName, Guid? parentId, CancellationToken cancellationToken = default) - { - if (container == null) - throw new ArgumentNullException(nameof(container)); - - if (file == null) - throw new ArgumentNullException(nameof(file)); - - if (string.IsNullOrWhiteSpace(newName)) - { - throw new ArgumentException($"'{nameof(newName)}' cannot be null or whitespace.", nameof(newName)); - } - - file.ChangeParentId(parentId ?? Guid.Empty); - file.SetFileName(newName); - - if (!file.IsDirectory) - file.UpdateMimeType(FileMimeTypeProvider.Get(newName)); - - await CheckFileExtensionAsync(container, file); - - return file; - } - - [UnitOfWork] - public virtual async Task DeleteAsync(FileContainer container, File file, CancellationToken cancellationToken = default) - { - await FileRepository.DeleteAsync(file); - - if (container.AutoDeleteBlob && !file.IsDirectory) - { - var blobContainer = await FileBlobContainerProvider.GetAsync(container, cancellationToken: cancellationToken); - - await blobContainer.DeleteAsync(file.BlobName, cancellationToken); - } - } - - [UnitOfWork] - public virtual async Task ClearContainerFilesAsync(FileContainer container, CancellationToken cancellationToken = default) - { - // TODO: performance - - var files = await FileRepository.GetListAsync(containerId: container.Id, cancellationToken: cancellationToken); - - foreach (var file in files) - { - await FileRepository.DeleteAsync(file); - - if (container.AutoDeleteBlob && !file.IsDirectory) - { - var blobContainer = await FileBlobContainerProvider.GetAsync(container, cancellationToken: cancellationToken); - - await blobContainer.DeleteAsync(file.BlobName, cancellationToken); - } - } - } - - public virtual async Task GetFileBytesByFileIdAsync(string containerName, Guid id, CancellationToken cancellationToken = default) - { - var container = await FileContainerRepository.GetByNameAsync(containerName, cancellationToken); - var file = await FileRepository.GetAsync(id, cancellationToken: cancellationToken); - return await GetFileBytesAsync(container, file, cancellationToken); - } - - public virtual async Task GetFileSteamByFileIdAsync(string containerName, Guid id, CancellationToken cancellationToken = default) - { - var container = await FileContainerRepository.GetByNameAsync(containerName, cancellationToken); - var file = await FileRepository.GetAsync(id, cancellationToken: cancellationToken); - return await GetFileSteamAsync(container, file, cancellationToken); - } - - public virtual async Task GetByIdAsync(string containerName, Guid id, CancellationToken cancellationToken = default) - { - return await FileRepository.GetAsync(id, cancellationToken: cancellationToken); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileMimeTypeProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileMimeTypeProvider.cs deleted file mode 100644 index 415f2ac..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileMimeTypeProvider.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.IO; -using HeyRed.Mime; - -namespace Passingwind.Abp.FileManagement.Files; - -public class FileMimeTypeProvider : IFileMimeTypeProvider -{ - public string Get(string fileName) - { - if (string.IsNullOrWhiteSpace(fileName)) - { - throw new ArgumentException($"'{nameof(fileName)}' cannot be null or whitespace.", nameof(fileName)); - } - - return MimeTypesMap.GetMimeType(Path.GetExtension(fileName)); - } -} \ No newline at end of file diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileNameDuplicateDetectionProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileNameDuplicateDetectionProvider.cs deleted file mode 100644 index 42e2f88..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/FileNameDuplicateDetectionProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Repositories; - -namespace Passingwind.Abp.FileManagement.Files; - -public class FileNameDuplicateDetectionProvider : IFileDuplicateDetectionProvider -{ - private readonly IFileRepository _fileRepository; - - public FileNameDuplicateDetectionProvider(IFileRepository fileRepository) - { - _fileRepository = fileRepository; - } - - public virtual async Task IsExistsAsync(FileContainer fileContainer, File file, CancellationToken cancellationToken = default) - { - return await _fileRepository.AnyAsync(x => x.Id != file.Id - && x.FileName == file.FileName - && x.ParentId == file.ParentId - && x.ContainerId == file.ContainerId - && x.IsDirectory == file.IsDirectory, - cancellationToken); - } -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenProvider.cs deleted file mode 100644 index df0ce1d..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenProvider.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileAccessTokenProvider -{ - Task CreateAsync(FileContainer container, File file, TimeSpan? expiration = null, CancellationToken cancellationToken = default); - - Task ValidAsync(string token, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenRepository.cs deleted file mode 100644 index 83fe086..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileAccessTokenRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; -using Volo.Abp.Domain.Repositories; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileAccessTokenRepository : IRepository -{ -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileBlobNameGenerator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileBlobNameGenerator.cs deleted file mode 100644 index 9baabee..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileBlobNameGenerator.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileBlobNameGenerator -{ - Task CreateAsync(Guid containerId, Guid fileId, string uniqueId, string fileName, string mimeType, long length, string hash, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileDuplicateDetectionProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileDuplicateDetectionProvider.cs deleted file mode 100644 index a7200a4..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileDuplicateDetectionProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileDuplicateDetectionProvider -{ - Task IsExistsAsync(FileContainer fileContainer, File file, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileInfoCheckProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileInfoCheckProvider.cs deleted file mode 100644 index 0721f8b..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileInfoCheckProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileInfoCheckProvider : ITransientDependency -{ - /// - /// check file or directory when create or update - /// - /// - /// - /// - Task CheckAsync(FileContainer container, File file, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileManager.cs deleted file mode 100644 index 7efa534..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileManager.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Services; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileManager : IDomainService -{ - Task FindFileAsync(FileContainer container, string fileName, Guid? parentId, CancellationToken cancellationToken = default); - - /// - /// Override an exist file with bytes - /// - /// - /// - /// - /// - Task UpdateFileAsync(FileContainer container, File file, byte[] bytes, CancellationToken cancellationToken = default); - - /// - /// Create an new file with bytes - /// - /// - /// - /// - /// - /// - /// - Task CreateFileAsync(FileContainer container, string fileName, string mimeType, byte[] bytes, Guid? parentId = null, CancellationToken cancellationToken = default); - - Task CreateDirectoryAsync(FileContainer container, string name, Guid? parentId, CancellationToken cancellationToken = default); - - Task ChangeNameAsync(FileContainer container, File file, string newName, Guid? parentId, CancellationToken cancellationToken = default); - - Task GetFileBytesAsync(FileContainer container, File file, CancellationToken cancellationToken = default); - Task GetFileSteamAsync(FileContainer container, File file, CancellationToken cancellationToken = default); - - Task IsFileExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default); - Task IsDirectoryExistsAsync(FileContainer container, File file, CancellationToken cancellationToken = default); - - Task SaveBlobAsync(FileContainer container, File file, byte[] bytes, CancellationToken cancellationToken = default); - Task SaveBlobAsync(FileContainer container, File file, Stream stream, CancellationToken cancellationToken = default); - - /// - /// Delete an file - /// - /// - /// - /// - Task DeleteAsync(FileContainer container, File file, CancellationToken cancellationToken = default); - - /// - /// Delete all files - /// - /// - /// - Task ClearContainerFilesAsync(FileContainer container, CancellationToken cancellationToken = default); - - Task GetFileBytesByFileIdAsync(string containerName, Guid id, CancellationToken cancellationToken = default); - Task GetFileSteamByFileIdAsync(string containerName, Guid id, CancellationToken cancellationToken = default); - - Task GetByIdAsync(string containerName, Guid id, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRenameProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRenameProvider.cs deleted file mode 100644 index 8f64133..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRenameProvider.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileRenameProvider -{ - Task GetAsync(FileContainer container, string fileName, Guid? parentId, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRepository.cs deleted file mode 100644 index 007b00e..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileRepository.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Repositories; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileRepository : IRepository -{ - Task GetCountAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default); - - Task> GetListAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, bool includeDetails = false, CancellationToken cancellationToken = default); - - Task> GetPagedListAsync(int skipCount, int maxResultCount, string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default); - - Task> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default); - - Task IsFileNameExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); - - Task FindByNameAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); - - Task GetByNameAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileUniqueIdGenerator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileUniqueIdGenerator.cs deleted file mode 100644 index 7aea360..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileUniqueIdGenerator.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Passingwind.Abp.FileManagement.Files; - -public interface IFileUniqueIdGenerator -{ - Task CreateAsync(FileContainer fileContainer, Guid fileId, CancellationToken cancellationToken = default); -} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenProvider.cs new file mode 100644 index 0000000..2ef3f85 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenProvider.cs @@ -0,0 +1,9 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileAccessTokenProvider +{ + Task VerifyAsync(string token, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenRepository.cs new file mode 100644 index 0000000..0a59329 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileAccessTokenRepository.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileAccessTokenRepository : IRepository +{ + Task GetCountAsync(Guid containerId, Guid? fileId = null, Guid? userId = null, CancellationToken cancellationToken = default); + Task> GetListAsync(Guid containerId, Guid? fileId = null, Guid? userId = null, CancellationToken cancellationToken = default); + Task> GetPagedListAsync(int skipCount, int maxResultCount, Guid containerId, Guid? fileId = null, Guid? userId = null, string? sorting = null, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileBlobContainerProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileBlobContainerProvider.cs similarity index 83% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileBlobContainerProvider.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileBlobContainerProvider.cs index 6d53e27..6544e9f 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileBlobContainerProvider.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileBlobContainerProvider.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Volo.Abp.BlobStoring; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public interface IFileBlobContainerProvider { diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileBlobNameGenerator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileBlobNameGenerator.cs new file mode 100644 index 0000000..f39e100 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileBlobNameGenerator.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileBlobNameGenerator +{ + Task CreateAsync(Guid containerId, Guid fileId, string uniqueId, string fileName, string? mimeType = null, long? length = null, string? hash = null, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerAccessProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerAccessProvider.cs new file mode 100644 index 0000000..34826b1 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerAccessProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileContainerAccessProvider +{ + Task IsGrantedAsync(string name, string providerName, Guid providerId, CancellationToken cancellationToken = default); + Task IsGrantedAsync(Guid containerId, string providerName, Guid providerId, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerManager.cs new file mode 100644 index 0000000..5db5b48 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerManager.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Passingwind.Abp.FileManagement.Files; +using Volo.Abp.Domain.Services; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileContainerManager : IDomainService +{ + Task CheckExistsAsync(string name, CancellationToken cancellationToken = default); + Task IsExistsAsync(string name, CancellationToken cancellationToken = default); + Task IsExistsAsync(FileContainer fileContainer, CancellationToken cancellationToken = default); + + Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default); + Task GetByNameAsync(string name, CancellationToken cancellationToken = default); + + Task CreateAsync( + string name, + FileAccessMode accessMode = FileAccessMode.Authorized, + FileOverrideBehavior overrideBehavior = FileOverrideBehavior.None, + string? description = null, + long? maximumEachFileSize = null, + int? maximumFileQuantity = null, + bool? allowAnyFileExtension = null, + string? allowedFileExtensions = null, + string? prohibitedFileExtensions = null, + bool? autoDeleteBlob = false); + + Task UpdateAsync(FileContainer fileContainer, CancellationToken cancellationToken = default); + + Task DeleteAsync(FileContainer fileContainer, CancellationToken cancellationToken = default); + Task CanAccessAsync(string name, string providerName, Guid providerId, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileContainerRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerRepository.cs similarity index 86% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileContainerRepository.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerRepository.cs index cb72462..d308db7 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileContainerRepository.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileContainerRepository.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public interface IFileContainerRepository : IRepository { @@ -14,7 +14,7 @@ public interface IFileContainerRepository : IRepository Task> GetPagedListAsync(int skipCount, int maxResultCount, string? filter = null, Guid? userId = null, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default); - Task CheckExistsAsync(FileContainer fileContainer, CancellationToken cancellationToken = default); + Task IsNameExistsAsync(string name, Guid[]? excludeIds = null, CancellationToken cancellationToken = default); Task FindByNameAsync(string name, CancellationToken cancellationToken = default); diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileDuplicateDetectionProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileDuplicateDetectionProvider.cs new file mode 100644 index 0000000..bcc7a54 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileDuplicateDetectionProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Passingwind.Abp.FileManagement; + +[Obsolete] +public interface IFileNameDuplicateDetectionProvider +{ + Task IsExistsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileHashCalculator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileHashCalculator.cs similarity index 83% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileHashCalculator.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileHashCalculator.cs index b32e7f8..d4ba453 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileHashCalculator.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileHashCalculator.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Volo.Abp.DependencyInjection; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public interface IFileHashCalculator : ISingletonDependency { diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileInfoCheckProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileInfoCheckProvider.cs new file mode 100644 index 0000000..701fd63 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileInfoCheckProvider.cs @@ -0,0 +1,19 @@ +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileInfoCheckProvider : ITransientDependency +{ + /// + /// check file or directory when create or update + /// + /// + /// + /// + /// + /// + Task CheckAsync(FileContainer container, string fileName, string mimeType, long length, CancellationToken cancellationToken = default); + Task IsValidAsync(FileContainer container, string fileName, string mimeType, long length, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileManager.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileManager.cs new file mode 100644 index 0000000..00d1992 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileManager.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileManager : IDomainService +{ + Task FindAsync(Guid fileId, CancellationToken cancellationToken = default); + Task GetAsync(Guid fileId, CancellationToken cancellationToken = default); + + Task FindAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task FindAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task GetAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task GetAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task FindFileAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task FindFileAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task GetFileAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task GetFileAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task FindDirectoryAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task FindDirectoryAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task GetDirectoryAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task GetDirectoryAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task> GetFilesAsync(string container, string directoryName, Guid? parentId = null, bool includeSubDirectory = false, CancellationToken cancellationToken = default); + Task> GetFilesAsync(Guid containerId, string directoryName, Guid? parentId = null, bool includeSubDirectory = false, CancellationToken cancellationToken = default); + Task> GetFilesAsync(Guid containerId, Guid directoryId, bool includeSubDirectory = false, CancellationToken cancellationToken = default); + + Task IsExistsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task IsExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task IsFileExistsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task IsFileExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task IsDirectoryExistsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task IsDirectoryExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task GetFileBytesAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task GetFileBytesAsync(string container, Guid fileId, CancellationToken cancellationToken = default); + Task GetFileBytesAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default); + + Task GetFileSteamAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task GetFileSteamAsync(string container, Guid fileId, CancellationToken cancellationToken = default); + Task GetFileSteamAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default); + + Task CreateDirectoryAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task CreateDirectoryAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task ChangeFileNameAsync(string container, string fileName, string newFileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task ChangeFileNameAsync(Guid containerId, string fileName, string newFileName, Guid? parentId = null, CancellationToken cancellationToken = default); + + Task SaveAsync(string container, string fileName, Stream stream, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default); + Task SaveAsync(string container, string fileName, byte[] bytes, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default); + Task SaveAsync(Guid containerId, string fileName, Stream stream, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default); + Task SaveAsync(Guid containerId, string fileName, byte[] bytes, string? mimeType = null, Guid? parentId = null, bool ignoreCheck = false, bool overrideExisting = false, CancellationToken cancellationToken = default); + + Task DeleteAsync(string container, string fileName, Guid? parentId = null, bool forceDelete = false, CancellationToken cancellationToken = default); + Task DeleteAsync(string container, Guid fileId, bool forceDelete = false, CancellationToken cancellationToken = default); + Task DeleteAsync(Guid containerId, Guid fileId, bool forceDelete = false, CancellationToken cancellationToken = default); + + Task ClearContainerFilesAsync(string container, CancellationToken cancellationToken = default); + Task ClearContainerFilesAsync(Guid containerId, CancellationToken cancellationToken = default); + + Task GetFileCountAsync(string container, CancellationToken cancellationToken = default); + + Task IsValidAsync(string container, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default); + Task IsValidAsync(Guid containerId, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default); + + Task CheckAsync(string container, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default); + Task CheckAsync(Guid containerId, string fileName, long length, string? mimeType = null, CancellationToken cancellationToken = default); + + Task IsReadOnlyAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task IsReadOnlyAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task IsReadOnlyAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default); + + Task SetReadOnlyAsync(Guid containerId, Guid fileId, bool isReadOnly, CancellationToken cancellationToken = default); + + Task> GetTagsAsync(string container, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task> GetTagsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default); + Task> GetTagsAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default); + + Task SetTagsAsync(Guid containerId, Guid fileId, IEnumerable tags, CancellationToken cancellationToken = default); + + Task GenerateTokenAsync(Guid containerId, Guid fileId, CancellationToken cancellationToken = default); + Task CreateAccessTokenAsync(Guid containerId, Guid fileId, TimeSpan? expiration = null, CancellationToken cancellationToken = default); + Task FindAccessTokenAsync(Guid tokenId, CancellationToken cancellationToken = default); + + Task CreateArchiveAsync(string container, Guid fileId, string archiveFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); + Task CreateArchiveAsync(Guid containerId, Guid fileId, string archiveFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); + + Task UnarchiveAsync(string container, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); + Task UnarchiveAsync(Guid containerId, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); + + Task CopyFileAsync(Guid containerId, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); + Task CopyFileAsync(string container, Guid fileId, string targetFileName, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); + + Task CopyDirectoryAsync(Guid containerId, Guid fileId, string targetFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); + Task CopyDirectoryAsync(string container, Guid fileId, string targetFileName, bool includeSubDirectory = true, Guid? targetParentId = null, bool overrideExisting = false, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileMimeTypeProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileMimeTypeProvider.cs similarity index 74% rename from modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileMimeTypeProvider.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileMimeTypeProvider.cs index 6e54ea0..d9b2543 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/Files/IFileMimeTypeProvider.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileMimeTypeProvider.cs @@ -1,6 +1,6 @@ using Volo.Abp.DependencyInjection; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; public interface IFileMimeTypeProvider : ITransientDependency { diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRenameProvider.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRenameProvider.cs new file mode 100644 index 0000000..c966bbd --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRenameProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileRenameProvider +{ + Task RenameAsync(string container, string fileName, Guid? parentId = null, bool isDirectory = false, CancellationToken cancellationToken = default); + Task RenameAsync(FileContainer container, string fileName, Guid? parentId = null, bool isDirectory = false, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRepository.cs new file mode 100644 index 0000000..a9d23e3 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileRepository.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileRepository : IRepository +{ + Task GetCountAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default); + + Task> GetListAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, bool includeDetails = false, CancellationToken cancellationToken = default); + + Task> GetPagedListAsync(int skipCount, int maxResultCount, string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default); + + Task> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default); + + Task IsFileNameExistsAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default); + + Task FindByNameAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default); + + Task GetByNameAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileUniqueIdGenerator.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileUniqueIdGenerator.cs new file mode 100644 index 0000000..6cfa5db --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.Domain/IFileUniqueIdGenerator.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Passingwind.Abp.FileManagement; + +public interface IFileUniqueIdGenerator +{ + Task CreateAsync(Guid containerId, Guid fileId, string fileName, bool isDirectory, CancellationToken cancellationToken = default); +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContext.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContext.cs index e7f213d..d9e8ebc 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContext.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContext.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -9,7 +8,7 @@ namespace Passingwind.Abp.FileManagement.EntityFrameworkCore; public class FileManagementDbContext : AbpDbContext, IFileManagementDbContext { public DbSet FileContainers { get; set; } - public DbSet Files { get; set; } + public DbSet Files { get; set; } public DbSet FileAccessTokens { get; set; } public FileManagementDbContext(DbContextOptions options) diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContextModelCreatingExtensions.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContextModelCreatingExtensions.cs index 7c5fc76..b76e135 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContextModelCreatingExtensions.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/FileManagementDbContextModelCreatingExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp; using Volo.Abp.EntityFrameworkCore.Modeling; @@ -18,37 +17,63 @@ public static void ConfigureFileManagement( b.ToTable(FileManagementDbProperties.DbTablePrefix + "FileContainers", FileManagementDbProperties.DbSchema); b.ConfigureByConvention(); - b.Property(q => q.Name).IsRequired().HasMaxLength(FileManagementConsts.MaxFileContainerNameLength); - b.Property(q => q.Description).HasMaxLength(FileManagementConsts.MaxFileContainerDescriptionLength); + b.Property(x => x.Name).IsRequired().HasMaxLength(FileManagementConsts.MaxFileContainerNameLength); + b.Property(x => x.Description).HasMaxLength(FileManagementConsts.MaxFileContainerDescriptionLength); - b.HasIndex(q => q.Name); + b.HasMany(x => x.Accesses).WithOne().HasForeignKey(x => x.FileContainerId); + + b.HasIndex(x => x.Name); }) - .Entity(b => + .Entity(b => + { + b.ToTable(FileManagementDbProperties.DbTablePrefix + "FileContainerAccesses", FileManagementDbProperties.DbSchema); + b.ConfigureByConvention(); + + b.Property(x => x.ProviderName).IsRequired().HasMaxLength(64); + b.Property(x => x.ProviderKey).IsRequired().HasMaxLength(64); + + b.HasKey(x => new { x.FileContainerId, x.ProviderName, x.ProviderKey }); + }) + .Entity(b => { b.ToTable(FileManagementDbProperties.DbTablePrefix + "Files", FileManagementDbProperties.DbSchema); b.ConfigureByConvention(); - b.Property(q => q.FileName).IsRequired().HasMaxLength(FileManagementConsts.MaxFileItemFileNameLength); - b.Property(q => q.MimeType).HasMaxLength(FileManagementConsts.MaxFileItemMimeTypeLength); - b.Property(q => q.BlobName).IsRequired().HasMaxLength(FileManagementConsts.MaxFileItemBlobNameLength); - b.Property(q => q.Hash).HasMaxLength(FileManagementConsts.MaxFileItemHashLength); - b.Property(q => q.UniqueId).IsRequired().HasMaxLength(FileManagementConsts.MaxFileItemUniqueIdLength); - - b.HasIndex(q => q.ContainerId); - b.HasIndex(q => q.FileName); - b.HasIndex(q => q.Hash); - b.HasIndex(q => q.UniqueId); - b.HasIndex(q => q.CreationTime).IsDescending(); + b.Property(x => x.FileName).IsRequired().HasMaxLength(FileManagementConsts.MaxFileItemFileNameLength); + b.Property(x => x.MimeType).HasMaxLength(FileManagementConsts.MaxFileItemMimeTypeLength); + b.Property(x => x.BlobName).IsRequired().HasMaxLength(FileManagementConsts.MaxFileItemBlobNameLength); + b.Property(x => x.Hash).HasMaxLength(FileManagementConsts.MaxFileItemHashLength); + b.Property(x => x.UniqueId).IsRequired().HasMaxLength(FileManagementConsts.MaxFileItemUniqueIdLength); + + b.HasMany(x => x.Tags).WithOne().HasForeignKey(x => x.FileId); + + b.HasIndex(x => x.ContainerId); + b.HasIndex(x => x.FileName); + b.HasIndex(x => x.Hash); + b.HasIndex(x => x.UniqueId); + b.HasIndex(x => x.CreationTime).IsDescending(); + }) + .Entity(b => + { + b.ToTable(FileManagementDbProperties.DbTablePrefix + "FileTags", FileManagementDbProperties.DbSchema); + b.ConfigureByConvention(); + + b.Property(x => x.Tags).IsRequired().HasMaxLength(FileManagementConsts.MaxFileTagValueLength); + + b.HasKey(x => new { x.FileId, x.Tags }); }) .Entity(b => { b.ToTable(FileManagementDbProperties.DbTablePrefix + "FileAccessTokens", FileManagementDbProperties.DbSchema); b.ConfigureByConvention(); - b.Property(q => q.Token).IsRequired().HasMaxLength(FileManagementConsts.MaxFileAccessTokenTokenLength); + b.Property(x => x.Token).IsRequired().HasMaxLength(FileManagementConsts.MaxFileAccessTokenTokenLength); + + b.Property(x => x.FileName).IsRequired().HasMaxLength(FileManagementConsts.MaxFileItemFileNameLength); + b.Property(x => x.MimeType).HasMaxLength(FileManagementConsts.MaxFileItemMimeTypeLength); - b.HasIndex(q => q.Token); - b.HasIndex(q => q.FileId); + b.HasIndex(x => x.Token); + b.HasIndex(x => x.FileId); }); } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/IFileManagementDbContext.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/IFileManagementDbContext.cs index cf33815..e5ca460 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/IFileManagementDbContext.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/IFileManagementDbContext.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -9,6 +8,6 @@ namespace Passingwind.Abp.FileManagement.EntityFrameworkCore; public interface IFileManagementDbContext : IEfCoreDbContext { DbSet FileContainers { get; } - DbSet Files { get; } + DbSet Files { get; } DbSet FileAccessTokens { get; } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileAccessTokenRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileAccessTokenRepository.cs index ae25216..6bdadb2 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileAccessTokenRepository.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileAccessTokenRepository.cs @@ -1,5 +1,9 @@ -using System; -using Passingwind.Abp.FileManagement.Files; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -10,4 +14,39 @@ public class FileAccessTokenRepository : EfCoreRepository dbContextProvider) : base(dbContextProvider) { } + + public virtual async Task GetCountAsync(Guid containerId, Guid? fileId = null, Guid? userId = null, CancellationToken cancellationToken = default) + { + var dbset = await GetDbSetAsync(); + + return await dbset + .WhereIf(fileId.HasValue, x => x.FileId == fileId) + .WhereIf(userId.HasValue, x => x.CreatorId == userId) + .Where(x => x.ContainerId == containerId) + .LongCountAsync(cancellationToken); + } + + public virtual async Task> GetListAsync(Guid containerId, Guid? fileId = null, Guid? userId = null, CancellationToken cancellationToken = default) + { + var dbset = await GetDbSetAsync(); + + return await dbset + .WhereIf(fileId.HasValue, x => x.FileId == fileId) + .WhereIf(userId.HasValue, x => x.CreatorId == userId) + .Where(x => x.ContainerId == containerId) + .ToListAsync(cancellationToken); + } + + public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, Guid containerId, Guid? fileId = null, Guid? userId = null, string? sorting = null, CancellationToken cancellationToken = default) + { + var dbset = await GetDbSetAsync(); + + return await dbset + .WhereIf(fileId.HasValue, x => x.FileId == fileId) + .WhereIf(userId.HasValue, x => x.CreatorId == userId) + .Where(x => x.ContainerId == containerId) + .OrderByDescending(x => x.CreationTime) + .PageBy(skipCount, maxResultCount) + .ToListAsync(cancellationToken); + } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileContainerRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileContainerRepository.cs index cf7622f..2375242 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileContainerRepository.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileContainerRepository.cs @@ -1,11 +1,10 @@ +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 Microsoft.EntityFrameworkCore; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -18,11 +17,13 @@ public FileContainerRepository(IDbContextProvider dbCon { } - public virtual async Task CheckExistsAsync(FileContainer fileContainer, CancellationToken cancellationToken = default) + public virtual async Task IsNameExistsAsync(string name, Guid[]? excludeIds = null, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); - return await dbset.AnyAsync(x => x.Id != fileContainer.Id && x.Name == fileContainer.Name, cancellationToken); + return await dbset + .WhereIf(excludeIds?.Any() == true, x => !excludeIds!.Contains(x.Id)) + .AnyAsync(x => x.Name == name, cancellationToken: cancellationToken); } public virtual async Task GetCountAsync(string? filter = null, Guid? userId = null, CancellationToken cancellationToken = default) @@ -77,6 +78,8 @@ public virtual async Task IncrementFileCountAsync(string name, int adjustment = { var dbset = await GetDbSetAsync(); - await dbset.Where(x => x.Name == name).ExecuteUpdateAsync(x => x.SetProperty(s => s.FilesCount, s => s.FilesCount + adjustment), cancellationToken: cancellationToken); + await dbset + .Where(x => x.Name == name) + .ExecuteUpdateAsync(x => x.SetProperty(s => s.FilesCount, s => s.FilesCount + adjustment), cancellationToken: cancellationToken); } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileRepository.cs index b5e3fd3..35b331b 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileRepository.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.EntityFrameworkCore/EntityFrameworkCore/Repositories/FileRepository.cs @@ -1,89 +1,93 @@ -using System; +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 Microsoft.EntityFrameworkCore; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; namespace Passingwind.Abp.FileManagement.EntityFrameworkCore.Repositories; -public class FileRepository : EfCoreRepository, IFileRepository +public class FileRepository : EfCoreRepository, IFileRepository { public FileRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } - public virtual async Task FindByNameAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + public virtual async Task FindByNameAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); return await dbset - .WhereIf(parentId.HasValue, x => x.ParentId == parentId) + .Where(x => x.ParentId == (parentId ?? Guid.Empty)) + .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) .FirstOrDefaultAsync(x => x.ContainerId == containerId && x.FileName == fileName, cancellationToken: cancellationToken); } - public virtual async Task GetByNameAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + public virtual async Task GetByNameAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); var entity = await dbset - .WhereIf(parentId.HasValue, x => x.ParentId == parentId) + .Where(x => x.ParentId == (parentId ?? Guid.Empty)) + .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) .FirstOrDefaultAsync(x => x.ContainerId == containerId && x.FileName == fileName, cancellationToken: cancellationToken); - return entity ?? throw new EntityNotFoundException(); + return entity ?? throw new EntityNotFoundException(typeof(FileItem), fileName); } public virtual async Task GetCountAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); return await dbset + .Where(x => x.ParentId == (parentId ?? Guid.Empty)) .WhereIf(!string.IsNullOrEmpty(filter), x => x.FileName.Contains(filter!)) .WhereIf(containerId.HasValue, x => x.ContainerId == containerId) - .WhereIf(parentId.HasValue, x => x.ParentId == parentId) .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) .LongCountAsync(cancellationToken); } - public virtual async Task> GetListAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, bool includeDetails = false, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); return await dbset + .Where(x => x.ParentId == (parentId ?? Guid.Empty)) .WhereIf(!string.IsNullOrEmpty(filter), x => x.FileName.Contains(filter!)) .WhereIf(containerId.HasValue, x => x.ContainerId == containerId) - .WhereIf(parentId.HasValue, x => x.ParentId == parentId) .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) .ToListAsync(cancellationToken); } - public virtual async Task> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); return await dbset.Where(x => ids.Contains(x.Id)).ToListAsync(cancellationToken); } - public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); return await dbset + .Where(x => x.ParentId == (parentId ?? Guid.Empty)) .WhereIf(!string.IsNullOrEmpty(filter), x => x.FileName.Contains(filter!)) .WhereIf(containerId.HasValue, x => x.ContainerId == containerId) - .WhereIf(parentId.HasValue, x => x.ParentId == parentId) .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) - .OrderBy(sorting ?? nameof(File.CreationTime) + " desc") + .OrderBy(sorting ?? nameof(FileItem.CreationTime) + " desc") .PageBy(skipCount, maxResultCount) .ToListAsync(cancellationToken); } - public virtual async Task IsFileNameExistsAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + public virtual async Task IsFileNameExistsAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) { var dbset = await GetDbSetAsync(); + return await dbset - .Where(x => x.ContainerId == containerId && x.FileName == fileName && x.ParentId == parentId) + .Where(x => x.ParentId == (parentId ?? Guid.Empty)) + .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) + .Where(x => x.ContainerId == containerId && x.FileName == fileName) .AnyAsync(cancellationToken); } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileAdminController.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileAdminController.cs new file mode 100644 index 0000000..6bb79f7 --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileAdminController.cs @@ -0,0 +1,107 @@ +using Microsoft.AspNetCore.Mvc; +using Passingwind.Abp.FileManagement.Files; +using System; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; + +namespace Passingwind.Abp.FileManagement; + +[Area(FileManagementRemoteServiceConsts.RemoteServiceName)] +[RemoteService(Name = FileManagementRemoteServiceConsts.RemoteServiceName)] +[Route("api/file-management/containers/{containerId}/files")] +public class FileAdminController : FileManagementController, IFileAdminAppService +{ + private readonly IFileAdminAppService _service; + + public FileAdminController(IFileAdminAppService service) + { + _service = service; + } + + /// + [HttpGet] + public virtual Task> GetListAsync(Guid containerId, FilePagedListRequestDto input) + { + return _service.GetListAsync(containerId, input); + } + + /// + [HttpGet("{id}")] + public virtual Task GetAsync(Guid containerId, Guid id) + { + return _service.GetAsync(containerId, id); + } + + /// + [HttpPost("directories")] + public virtual Task CreateDirectoryAsync(Guid containerId, FileDirectoryCreateDto input) + { + return _service.CreateDirectoryAsync(containerId, input); + } + + /// + [HttpPost] + public virtual Task CreateAsync(Guid containerId, [FromForm] FileCreateDto input) + { + return _service.CreateAsync(containerId, input); + } + + /// + [NonAction] + public virtual Task CreateByStreamAsync(Guid containerId, FileCreateByStreamDto input) + { + return _service.CreateByStreamAsync(containerId, input); + } + + /// + [NonAction] + public virtual Task CreateByBytesAsync(Guid containerId, FileCreateByBytesDto input) + { + return _service.CreateByBytesAsync(containerId, input); + } + + /// + [HttpPut("{id}")] + public virtual Task UpdateAsync(Guid containerId, Guid id, FileUpdateDto input) + { + return _service.UpdateAsync(containerId, id, input); + } + + /// + [HttpPost("{id}/move")] + public virtual Task MoveAsync(Guid containerId, Guid id, FileMoveAdminRequestDto input) + { + return _service.MoveAsync(containerId, id, input); + } + + /// + [HttpGet("{id}/blob")] + public virtual Task GetBlobAsync(Guid containerId, Guid id) + { + return _service.GetBlobAsync(containerId, id); + } + + /// + [NonAction] + public virtual Task GeBlobStreamAsync(Guid containerId, Guid id) + { + return _service.GeBlobStreamAsync(containerId, id); + } + + /// + [NonAction] + public virtual Task GetBlobBytesAsync(Guid containerId, Guid id) + { + return _service.GetBlobBytesAsync(containerId, id); + } + + /// + [HttpDelete("{id}")] + public virtual Task DeleteAsync(Guid containerId, Guid id) + { + return _service.DeleteAsync(containerId, id); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileContainerController.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileContainerAdminController.cs similarity index 66% rename from modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileContainerController.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileContainerAdminController.cs index c79dd45..84da764 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileContainerController.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileContainerAdminController.cs @@ -1,25 +1,26 @@ -using System; +using Microsoft.AspNetCore.Mvc; +using Passingwind.Abp.FileManagement.Files; +using System; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; [Area(FileManagementRemoteServiceConsts.RemoteServiceName)] [RemoteService(Name = FileManagementRemoteServiceConsts.RemoteServiceName)] [Route("api/file-management/containers")] -public class FileContainerController : FileManagementController, IFileContainerAppService +public class FileContainerAdminController : FileManagementController, IFileContainerAdminAppService { - private readonly IFileContainerAppService _service; + private readonly IFileContainerAdminAppService _service; - public FileContainerController(IFileContainerAppService service) + public FileContainerAdminController(IFileContainerAdminAppService service) { _service = service; } [HttpGet] - public virtual Task> GetListAsync(FileContainerListRequestDto input) + public virtual Task> GetListAsync(FileContainerAdminListRequestDto input) { return _service.GetListAsync(input); } @@ -31,13 +32,13 @@ public virtual Task GetAsync(Guid id) } [HttpPost] - public virtual Task CreateAsync(FileContainerCreateDto input) + public virtual Task CreateAsync(FileContainerAdminCreateDto input) { return _service.CreateAsync(input); } [HttpPut("{id}")] - public virtual Task UpdateAsync(Guid id, FileContainerUpdateDto input) + public virtual Task UpdateAsync(Guid id, FileContainerAdminUpdateDto input) { return _service.UpdateAsync(id, input); } @@ -48,12 +49,6 @@ public virtual Task DeleteAsync(Guid id) return _service.DeleteAsync(id); } - [HttpGet("by-name/{name}")] - public virtual Task GetByNameAsync(string name) - { - return _service.GetByNameAsync(name); - } - [HttpGet("all")] public virtual Task> GetAllListAsync() { diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileContainerController.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileContainerController.cs new file mode 100644 index 0000000..670b57d --- /dev/null +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileContainerController.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Mvc; +using Passingwind.Abp.FileManagement.Files; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; + +namespace Passingwind.Abp.FileManagement; + +[Area(FileManagementRemoteServiceConsts.RemoteServiceName)] +[RemoteService(Name = FileManagementRemoteServiceConsts.RemoteServiceName)] +[Route("api/file-containers")] +public class FileContainerController : FileManagementController, IFileContainerAppService +{ + private readonly IFileContainerAppService _service; + + public FileContainerController(IFileContainerAppService service) + { + _service = service; + } + + /// + [HttpGet("all")] + public virtual Task> GetAllListAsync(FileContainerListRequestDto input) + { + return _service.GetAllListAsync(input); + } + + /// + [HttpGet("by-name/{name}")] + public virtual Task GetByNameAsync(string name) + { + return _service.GetByNameAsync(name); + } + + /// + [HttpGet("by-name/{name}/check-access")] + public virtual Task GetCanAccessAsync(string name) + { + return _service.GetCanAccessAsync(name); + } +} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileController.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileController.cs similarity index 81% rename from modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileController.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileController.cs index 5a32ab2..03adce1 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileController.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileController.cs @@ -1,16 +1,17 @@ -using System; +using Microsoft.AspNetCore.Mvc; +using Passingwind.Abp.FileManagement.Files; +using System; using System.IO; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Content; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; [Area(FileManagementRemoteServiceConsts.RemoteServiceName)] [RemoteService(Name = FileManagementRemoteServiceConsts.RemoteServiceName)] -[Route("api/file-management")] +[Route("api/files")] public class FileController : FileManagementController, IFileAppService { private readonly IFileAppService _service; @@ -45,7 +46,7 @@ public virtual Task GetAsync(string containerName, Guid id) } [NonAction] - public virtual Task GetBlobBytesAsync(string containerName, Guid id) + public virtual Task GetBlobBytesAsync(string containerName, Guid id) { return _service.GetBlobBytesAsync(containerName, id); } @@ -75,16 +76,10 @@ public virtual Task MoveAsync(string containerName, Guid id, FileMoveRe return _service.MoveAsync(containerName, id, input); } - [HttpDelete("{containerName}/{id}")] - public virtual Task DeleteAsync(string containerName, Guid id) + [HttpPut("{containerName}/{id}/rename")] + public virtual Task RenameAsync(string containerName, Guid id, FileUpdateDto input) { - return _service.DeleteAsync(containerName, id); - } - - [HttpPut("{containerName}/{id}")] - public virtual Task UpdateAsync(string containerName, Guid id, FileUpdateDto input) - { - return _service.UpdateAsync(containerName, id, input); + return _service.RenameAsync(containerName, id, input); } [HttpPost("{containerName}/directory")] diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileShareController.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileShareController.cs similarity index 54% rename from modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileShareController.cs rename to modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileShareController.cs index 37602c9..075965c 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileShareController.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/FileShareController.cs @@ -1,11 +1,13 @@ -using System; +using Microsoft.AspNetCore.Mvc; +using Passingwind.Abp.FileManagement.Files; +using System; using System.IO; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Application.Dtos; using Volo.Abp.Content; -namespace Passingwind.Abp.FileManagement.Files; +namespace Passingwind.Abp.FileManagement; [Area(FileManagementRemoteServiceConsts.RemoteServiceName)] [RemoteService(Name = FileManagementRemoteServiceConsts.RemoteServiceName)] @@ -19,19 +21,25 @@ public FileShareController(IFileShareAppService service) _service = service; } - [HttpPost("{containerName}/{id}/share")] + [HttpPost("{containerName}/files/{id}/shares")] public virtual Task CreateAsync(string containerName, Guid id, FileShareCreateRequestDto input) { return _service.CreateAsync(containerName, id, input); } - [HttpGet("share/{token}")] - public virtual Task GetAsync(string token) + [HttpDelete("shares/{id}")] + public virtual Task DeleteAsync(Guid id) { - return _service.GetAsync(token); + return _service.DeleteAsync(id); } - [HttpGet("share/{token}/blob")] + [HttpGet("shares/{id}")] + public virtual Task GetAsync(Guid id) + { + return _service.GetAsync(id); + } + + [HttpGet("shares/token/{token}/blob")] public virtual Task GetBlobAsync(string token) { return _service.GetBlobAsync(token); @@ -43,9 +51,21 @@ public virtual Task GetAsync(string token) return _service.GetBytesAsync(token); } + [HttpGet("shares")] + public virtual Task> GetListAsync(string containerName, FileShareListRequestDto input) + { + return _service.GetListAsync(containerName, input); + } + [NonAction] public virtual Task GetStreamAsync(string token) { return _service.GetStreamAsync(token); } + + [HttpPost("shares/token/{token}/verify")] + public virtual Task VerifyTokenAsync(string token) + { + return _service.VerifyTokenAsync(token); + } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileIntegrationController.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileIntegrationController.cs deleted file mode 100644 index bd29775..0000000 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.HttpApi/Files/FileIntegrationController.cs +++ /dev/null @@ -1,51 +0,0 @@ -//using System; -//using System.IO; -//using System.Threading.Tasks; -//using Microsoft.AspNetCore.Mvc; -//using Volo.Abp; - -//namespace Passingwind.Abp.FileManagement.Files; - -//[Area(FileManagementRemoteServiceConsts.RemoteServiceName)] -//[RemoteService(Name = FileManagementRemoteServiceConsts.RemoteServiceName)] -//[ControllerName("UserIntegration")] -//[Route("integration-api/file-management/files")] -//public class FileIntegrationController : FileManagementController, IFileIntegrationAppService -//{ -// private readonly IFileIntegrationAppService _fileIntegrationAppService; - -// public FileIntegrationController(IFileIntegrationAppService fileIntegrationAppService) -// { -// _fileIntegrationAppService = fileIntegrationAppService; -// } - -// public virtual Task CreateByBytesAsync(string containerName, FileCreateByBytesDto input) -// { -// return _fileIntegrationAppService.CreateByBytesAsync(containerName, input); -// } - -// public virtual Task CreateByStreamAsync(string containerName, FileCreateByStreamDto input) -// { -// return _fileIntegrationAppService.CreateByStreamAsync(containerName, input); -// } - -// public virtual Task GetAsync(string containerName, Guid id) -// { -// return _fileIntegrationAppService.GetAsync(containerName, id); -// } - -// public virtual Task GetBytesAsync(string containerName, Guid id) -// { -// return _fileIntegrationAppService.GetBytesAsync(containerName, id); -// } - -// public virtual Task GetContainerAsync(Guid id) -// { -// return _fileIntegrationAppService.GetContainerAsync(id); -// } - -// public virtual Task GetStreamAsync(string containerName, Guid id) -// { -// return _fileIntegrationAppService.GetStreamAsync(containerName, id); -// } -//} diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContext.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContext.cs index b886d6b..ff04d42 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContext.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContext.cs @@ -1,5 +1,4 @@ using MongoDB.Driver; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Data; using Volo.Abp.MongoDB; @@ -9,7 +8,7 @@ namespace Passingwind.Abp.FileManagement.MongoDB; public class FileManagementMongoDbContext : AbpMongoDbContext, IFileManagementMongoDbContext { public IMongoCollection FileContainers => Collection(); - public IMongoCollection Files => Collection(); + public IMongoCollection Files => Collection(); public IMongoCollection FileAccessTokens => Collection(); protected override void CreateModel(IMongoModelBuilder modelBuilder) diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContextExtensions.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContextExtensions.cs index 7f83a93..ced936f 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContextExtensions.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/FileManagementMongoDbContextExtensions.cs @@ -1,5 +1,4 @@ -using Passingwind.Abp.FileManagement.Files; -using Volo.Abp; +using Volo.Abp; using Volo.Abp.MongoDB; namespace Passingwind.Abp.FileManagement.MongoDB; @@ -12,7 +11,7 @@ public static void ConfigureFileManagement( Check.NotNull(builder, nameof(builder)); builder.Entity(options => options.CollectionName = FileManagementDbProperties.DbTablePrefix + "FileContainers"); - builder.Entity(options => options.CollectionName = FileManagementDbProperties.DbTablePrefix + "Files"); + builder.Entity(options => options.CollectionName = FileManagementDbProperties.DbTablePrefix + "Files"); builder.Entity(options => options.CollectionName = FileManagementDbProperties.DbTablePrefix + "FileAccessTokens"); } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/IFileManagementMongoDbContext.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/IFileManagementMongoDbContext.cs index 994f628..8aa366e 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/IFileManagementMongoDbContext.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/IFileManagementMongoDbContext.cs @@ -1,5 +1,4 @@ using MongoDB.Driver; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Data; using Volo.Abp.MongoDB; @@ -9,6 +8,6 @@ namespace Passingwind.Abp.FileManagement.MongoDB; public interface IFileManagementMongoDbContext : IAbpMongoDbContext { IMongoCollection FileContainers { get; } - IMongoCollection Files { get; } + IMongoCollection Files { get; } IMongoCollection FileAccessTokens { get; } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileAccessTokenRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileAccessTokenRepository.cs index 2480ac8..3bd6f1b 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileAccessTokenRepository.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileAccessTokenRepository.cs @@ -1,5 +1,10 @@ -using System; -using Passingwind.Abp.FileManagement.Files; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; @@ -10,4 +15,42 @@ public class FileAccessTokenRepository : MongoDbRepository dbContextProvider) : base(dbContextProvider) { } + + public virtual async Task GetCountAsync(Guid containerId, Guid? fileId = null, Guid? userId = null, CancellationToken cancellationToken = default) + { + var query = await GetMongoQueryableAsync(); + + return await query + .WhereIf(fileId.HasValue, x => x.FileId == fileId) + .WhereIf(userId.HasValue, x => x.CreatorId == userId) + .Where(x => x.ContainerId == containerId) + .As>() + .LongCountAsync(cancellationToken); + } + + public virtual async Task> GetListAsync(Guid containerId, Guid? fileId = null, Guid? userId = null, CancellationToken cancellationToken = default) + { + var query = await GetMongoQueryableAsync(); + + return await query + .WhereIf(fileId.HasValue, x => x.FileId == fileId) + .WhereIf(userId.HasValue, x => x.CreatorId == userId) + .Where(x => x.ContainerId == containerId) + .As>() + .ToListAsync(cancellationToken); + } + + public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, Guid containerId, Guid? fileId = null, Guid? userId = null, string? sorting = null, CancellationToken cancellationToken = default) + { + var query = await GetMongoQueryableAsync(); + + return await query + .WhereIf(fileId.HasValue, x => x.FileId == fileId) + .WhereIf(userId.HasValue, x => x.CreatorId == userId) + .Where(x => x.ContainerId == containerId) + .OrderByDescending(x => x.CreationTime) + .PageBy(skipCount, maxResultCount) + .As>() + .ToListAsync(cancellationToken); + } } diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileContainerRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileContainerRepository.cs index dff3742..b80ce7f 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileContainerRepository.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileContainerRepository.cs @@ -1,12 +1,11 @@ -using System; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using System; using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; -using MongoDB.Driver; -using MongoDB.Driver.Linq; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; @@ -19,11 +18,14 @@ public FileContainerRepository(IMongoDbContextProvider CheckExistsAsync(FileContainer fileContainer, CancellationToken cancellationToken = default) + public virtual async Task IsNameExistsAsync(string name, Guid[]? excludeIds = null, CancellationToken cancellationToken = default) { var query = await GetMongoQueryableAsync(); - return await query.AnyAsync(x => x.Id != fileContainer.Id && x.Name == fileContainer.Name, cancellationToken); + return await query + .WhereIf(excludeIds?.Any() == true, x => !excludeIds.Contains(x.Id)) + .As>() + .AnyAsync(x => x.Name == name, cancellationToken: cancellationToken); } public virtual async Task GetCountAsync(string? filter = null, Guid? userId = null, CancellationToken cancellationToken = default) @@ -77,10 +79,9 @@ public virtual async Task> GetPagedListAsync(int skipCount, .ToListAsync(cancellationToken); } - public virtual async Task IncrementFileCountAsync(string name, int adjustment=1, CancellationToken cancellationToken = default) + public virtual async Task IncrementFileCountAsync(string name, int adjustment = 1, CancellationToken cancellationToken = default) { - var dbContext = await GetDbContextAsync(cancellationToken); - var collection = dbContext.Collection(); + var collection = await GetCollectionAsync(cancellationToken); var update = new UpdateDefinitionBuilder(); diff --git a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileRepository.cs b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileRepository.cs index 8d8291c..2827c78 100644 --- a/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileRepository.cs +++ b/modules/file-management/src/Passingwind.Abp.FileManagement.MongoDB/MongoDB/Repositories/FileRepository.cs @@ -1,44 +1,45 @@ -using System; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using System; using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; -using MongoDB.Driver; -using MongoDB.Driver.Linq; -using Passingwind.Abp.FileManagement.Files; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; namespace Passingwind.Abp.FileManagement.MongoDB.Repositories; -public class FileRepository : MongoDbRepository, IFileRepository +public class FileRepository : MongoDbRepository, IFileRepository { public FileRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) { } - public virtual async Task FindByNameAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + public virtual async Task FindByNameAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) { var query = await GetMongoQueryableAsync(); return await query .WhereIf(parentId.HasValue, x => x.ParentId == parentId) - .As>() + .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) + .As>() .FirstOrDefaultAsync(x => x.ContainerId == containerId && x.FileName == fileName, cancellationToken: cancellationToken); } - public virtual async Task GetByNameAsync(Guid containerId, string fileName, Guid? parentId = null, CancellationToken cancellationToken = default) + public virtual async Task GetByNameAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) { var query = await GetMongoQueryableAsync(); var entity = await query .WhereIf(parentId.HasValue, x => x.ParentId == parentId) - .As>() + .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) + .As>() .FirstOrDefaultAsync(x => x.ContainerId == containerId && x.FileName == fileName, cancellationToken: cancellationToken); - return entity ?? throw new EntityNotFoundException(); + return entity ?? throw new EntityNotFoundException(typeof(FileItem), fileName); } public virtual async Task GetCountAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) @@ -50,11 +51,11 @@ public virtual async Task GetCountAsync(string? filter = null, Guid? conta .WhereIf(containerId.HasValue, x => x.ContainerId == containerId) .WhereIf(parentId.HasValue, x => x.ParentId == parentId) .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) - .As>() + .As>() .LongCountAsync(cancellationToken); } - public virtual async Task> GetListAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync(string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, bool includeDetails = false, CancellationToken cancellationToken = default) { var query = await GetMongoQueryableAsync(); @@ -63,18 +64,18 @@ public virtual async Task> GetListAsync(string? filter = null, Guid? .WhereIf(containerId.HasValue, x => x.ContainerId == containerId) .WhereIf(parentId.HasValue, x => x.ParentId == parentId) .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) - .As>() + .As>() .ToListAsync(cancellationToken); } - public virtual async Task> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) { var query = await GetMongoQueryableAsync(); return await query.Where(x => ids.Contains(x.Id)).ToListAsync(cancellationToken); } - public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, string? filter = null, Guid? containerId = null, Guid? parentId = null, bool? isDirectory = null, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default) { var query = await GetMongoQueryableAsync(); @@ -83,19 +84,20 @@ public virtual async Task> GetPagedListAsync(int skipCount, int maxRe .WhereIf(containerId.HasValue, x => x.ContainerId == containerId) .WhereIf(parentId.HasValue, x => x.ParentId == parentId) .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) - .OrderBy(sorting ?? nameof(File.CreationTime) + " desc") + .OrderBy(sorting ?? nameof(FileItem.CreationTime) + " desc") .PageBy(skipCount, maxResultCount) - .As>() + .As>() .ToListAsync(cancellationToken); } - public virtual async Task IsFileNameExistsAsync(Guid containerId, string fileName, Guid? parentId, CancellationToken cancellationToken = default) + public virtual async Task IsFileNameExistsAsync(Guid containerId, string fileName, Guid? parentId = null, bool? isDirectory = null, CancellationToken cancellationToken = default) { var query = await GetMongoQueryableAsync(); return await query .WhereIf(parentId.HasValue, x => x.ParentId == parentId) + .WhereIf(isDirectory.HasValue, x => x.IsDirectory == isDirectory) .Where(x => x.ContainerId == containerId && x.FileName == fileName) - .As>() + .As>() .AnyAsync(cancellationToken); } } diff --git a/modules/file-management/test/Directory.Build.props b/modules/file-management/test/Directory.Build.props new file mode 100644 index 0000000..d2b89c2 --- /dev/null +++ b/modules/file-management/test/Directory.Build.props @@ -0,0 +1,5 @@ + + + false + + diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileAdminAppServiceTests.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileAdminAppServiceTests.cs new file mode 100644 index 0000000..08c0f1a --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileAdminAppServiceTests.cs @@ -0,0 +1,227 @@ +using Microsoft.Extensions.Options; +using Passingwind.Abp.FileManagement; +using Passingwind.Abp.FileManagement.Files; +using Passingwind.Abp.FileManagement.Options; +using Shouldly; +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Passingwind.Abp.FileManagement; + +public class FileAdminAppServiceTests : FileManagementApplicationTestBase +{ + private readonly IFileAdminAppService _service; + + public FileAdminAppServiceTests() + { + _service = GetRequiredService(); + } + + //[Fact] + //public async Task GetListAsync_Empty() + //{ + // var result = await _service.GetListAsync(Guid.Empty,new FilePagedListRequestDto()); + + // result.TotalCount.ShouldBe(0); + //} + + //[Fact] + //public async Task GetListAsync_Test1() + //{ + // var result = await _service.GetListAsync(TestContainerId, new FilePagedListRequestDto()); + + // result.TotalCount.ShouldBeGreaterThan(0); + //} + + //[Fact] + //public async Task GetAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid id = default(global::System.Guid); + + // // Act + // var result = await service.GetAsync( + // containerId, + // id); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task DeleteAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid id = default(global::System.Guid); + + // // Act + // await service.DeleteAsync( + // containerId, + // id); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetBlobAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid id = default(global::System.Guid); + + // // Act + // var result = await service.GetBlobAsync( + // containerId, + // id); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GeBlobStreamAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid id = default(global::System.Guid); + + // // Act + // var result = await service.GeBlobStreamAsync( + // containerId, + // id); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetBlobBytesAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid id = default(global::System.Guid); + + // // Act + // var result = await service.GetBlobBytesAsync( + // containerId, + // id); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // FileCreateDto input = null; + + // // Act + // var result = await service.CreateAsync( + // containerId, + // input); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateByStreamAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // FileCreateByStreamDto input = null; + + // // Act + // var result = await service.CreateByStreamAsync( + // containerId, + // input); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateByBytesAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // FileCreateByBytesDto input = null; + + // // Act + // var result = await service.CreateByBytesAsync( + // containerId, + // input); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task MoveAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid id = default(global::System.Guid); + // FileMoveAdminRequestDto input = null; + + // // Act + // var result = await service.MoveAsync( + // containerId, + // id, + // input); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task UpdateAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid id = default(global::System.Guid); + // FileUpdateDto input = null; + + // // Act + // var result = await service.UpdateAsync( + // containerId, + // id, + // input); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateDirectoryAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var service = new FileAdminAppService(TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // FileDirectoryCreateDto input = null; + + // // Act + // var result = await service.CreateDirectoryAsync( + // containerId, + // input); + + // // Assert + // Assert.True(false); + //} +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestBase.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestBase.cs new file mode 100644 index 0000000..2a812f1 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestBase.cs @@ -0,0 +1,11 @@ +using System; + +namespace Passingwind.Abp.FileManagement; + +/* Inherit from this class for your application layer tests. + * See SampleAppService_Tests for example. + */ +public abstract class FileManagementApplicationTestBase : FileManagementTestBase +{ + protected Guid TestContainerId { get; }= Guid.NewGuid(); +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestModule.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestModule.cs new file mode 100644 index 0000000..6433804 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FileManagementApplicationTestModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; + +namespace Passingwind.Abp.FileManagement; + +[DependsOn( + typeof(FileManagementApplicationModule), + typeof(FileManagementDomainTestModule) + )] +public class FileManagementApplicationTestModule : AbpModule +{ + +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xml b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xsd b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xsd new file mode 100644 index 0000000..ffa6fc4 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.abppkg.json b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.abppkg.json new file mode 100644 index 0000000..a686451 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.abppkg.json @@ -0,0 +1,3 @@ +{ + "role": "lib.test" +} \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.csproj b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.csproj new file mode 100644 index 0000000..22add07 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Application.Tests/Passingwind.Abp.FileManagement.Application.Tests.csproj @@ -0,0 +1,17 @@ + + + + + + net7.0 + enable + Passingwind.Abp.FileManagement + + + + + + + + + diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestBase.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestBase.cs new file mode 100644 index 0000000..f87b44d --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestBase.cs @@ -0,0 +1,9 @@ +namespace Passingwind.Abp.FileManagement; + +/* Inherit from this class for your domain layer tests. + * See SampleManager_Tests for example. + */ +public abstract class FileManagementDomainTestBase : FileManagementTestBase +{ + protected string TestContainerName = "test-01"; +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestModule.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestModule.cs new file mode 100644 index 0000000..a8689f3 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagementDomainTestModule.cs @@ -0,0 +1,16 @@ +using Passingwind.Abp.FileManagement.EntityFrameworkCore; +using Volo.Abp.Modularity; + +namespace Passingwind.Abp.FileManagement; + +/* Domain tests are configured to use the EF Core provider. + * You can switch to MongoDB, however your domain tests should be + * database independent anyway. + */ +[DependsOn( + typeof(FileManagementEntityFrameworkCoreTestModule) + )] +public class FileManagementDomainTestModule : AbpModule +{ + +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagerTests.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagerTests.cs new file mode 100644 index 0000000..66be667 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FileManagerTests.cs @@ -0,0 +1,1574 @@ +using Shouldly; +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Passingwind.Abp.FileManagement; + +public class FileManagerTests : FileManagementDomainTestBase +{ + private readonly IFileManager _manager; + + public FileManagerTests() + { + _manager = GetRequiredService(); + } + + [Fact] + public async Task Test_IsExists_01() + { + // Arrange ; + string container = TestContainerName; + string fileName = Guid.NewGuid().ToString() + ".txt"; + Guid? parentId = null; + + // Act + var result = await _manager.IsExistsAsync( + container, + fileName, + parentId); + + // Assert + result.ShouldBe(false); + + // Act + result = await _manager.IsExistsAsync( + Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f30"), + fileName, + parentId); + + // Assert + result.ShouldBe(false); + } + + [Fact] + public async Task Test_IsExists_02() + { + // Arrange ; + var containerId = Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f30"); + string fileName = Guid.NewGuid().ToString() + ".txt"; + Guid? parentId = null; + + // Act + var entity = await _manager.SaveAsync(containerId, fileName, new byte[0]); + + // Assert + entity.ShouldNotBeNull(); + + // Assert + (await _manager.IsExistsAsync(containerId, fileName, parentId)).ShouldBe(true); + (await _manager.IsFileExistsAsync(containerId, fileName, parentId)).ShouldBe(true); + (await _manager.IsDirectoryExistsAsync(containerId, fileName, parentId)).ShouldBe(false); + } + + [Fact] + public async Task Test_IsExists_03() + { + // Arrange ; + var containerId = Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f30"); + string fileName = Guid.NewGuid().ToString(); + Guid? parentId = null; + + // Act + var entity = await _manager.CreateDirectoryAsync(containerId, fileName, parentId); + + // Assert + entity.ShouldNotBeNull(); + + // Assert + (await _manager.IsExistsAsync(containerId, fileName, parentId)).ShouldBe(true); + (await _manager.IsDirectoryExistsAsync(containerId, fileName, parentId)).ShouldBe(true); + (await _manager.IsFileExistsAsync(containerId, fileName, parentId)).ShouldBe(false); + } + + //[Fact] + //public async Task ChangeFileNameAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // string newFileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.ChangeFileNameAsync( + // containerId, + // fileName, + // newFileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task ChangeFileNameAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // string newFileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.ChangeFileNameAsync( + // container, + // fileName, + // newFileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CheckAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // long length = 0; + // string? mimeType = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.CheckAsync( + // container, + // fileName, + // length, + // mimeType, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CheckAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // long length = 0; + // string? mimeType = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.CheckAsync( + // containerId, + // fileName, + // length, + // mimeType, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task ClearContainerFilesAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.ClearContainerFilesAsync( + // containerId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task ClearContainerFilesAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.ClearContainerFilesAsync( + // container, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CopyDirectoryAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // string targetFileName = null; + // bool includeSubDirectory = false; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.CopyDirectoryAsync( + // containerId, + // fileId, + // targetFileName, + // includeSubDirectory, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CopyDirectoryAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // Guid fileId = default(global::System.Guid); + // string targetFileName = null; + // bool includeSubDirectory = false; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.CopyDirectoryAsync( + // container, + // fileId, + // targetFileName, + // includeSubDirectory, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CopyFileAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // string targetFileName = null; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.CopyFileAsync( + // containerId, + // fileId, + // targetFileName, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CopyFileAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // Guid fileId = default(global::System.Guid); + // string targetFileName = null; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.CopyFileAsync( + // container, + // fileId, + // targetFileName, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateAccessTokenAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // TimeSpan? expiration = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.CreateAccessTokenAsync( + // containerId, + // fileId, + // expiration, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateArchiveAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // string archiveFileName = null; + // bool includeSubDirectory = false; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.CreateArchiveAsync( + // containerId, + // fileId, + // archiveFileName, + // includeSubDirectory, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateArchiveAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // Guid fileId = default(global::System.Guid); + // string archiveFileName = null; + // bool includeSubDirectory = false; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.CreateArchiveAsync( + // container, + // fileId, + // archiveFileName, + // includeSubDirectory, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateDirectoryAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.CreateDirectoryAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task CreateDirectoryAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.CreateDirectoryAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task DeleteAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // bool forceDelete = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.DeleteAsync( + // container, + // fileName, + // parentId, + // forceDelete, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task DeleteAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // Guid fileId = default(global::System.Guid); + // bool forceDelete = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.DeleteAsync( + // container, + // fileId, + // forceDelete, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task DeleteAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // bool forceDelete = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.DeleteAsync( + // containerId, + // fileId, + // forceDelete, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindAccessTokenAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid tokenId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindAccessTokenAsync( + // tokenId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindAsync( + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindDirectoryAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindDirectoryAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindDirectoryAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindDirectoryAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindFileAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindFileAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task FindFileAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.FindFileAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GenerateTokenAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GenerateTokenAsync( + // containerId, + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetAsync( + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetDirectoryAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetDirectoryAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetDirectoryAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetDirectoryAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileBytesAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileBytesAsync( + // container, + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileBytesAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileBytesAsync( + // containerId, + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileBytesAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileBytesAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileCountAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileCountAsync( + // container, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileSteamAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileSteamAsync( + // container, + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileSteamAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileSteamAsync( + // containerId, + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFileSteamAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFileSteamAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetTagsAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetTagsAsync( + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetTagsAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetTagsAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetTagsAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetTagsAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetTagsAsync_StateUnderTest_ExpectedBehavior3() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetTagsAsync( + // containerId, + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsDirectoryExistsAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsDirectoryExistsAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsDirectoryExistsAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsDirectoryExistsAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsExistsAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsExistsAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsFileExistsAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsFileExistsAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsFileExistsAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsFileExistsAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsReadOnlyAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsReadOnlyAsync( + // container, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsReadOnlyAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid fileId = default(global::System.Guid); + // bool isReadOnly = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsReadOnlyAsync( + // fileId, + // isReadOnly, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsReadOnlyAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Guid? parentId = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsReadOnlyAsync( + // containerId, + // fileName, + // parentId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsReadOnlyAsync_StateUnderTest_ExpectedBehavior3() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsReadOnlyAsync( + // containerId, + // fileId, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsValidAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // long length = 0; + // string? mimeType = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsValidAsync( + // container, + // fileName, + // length, + // mimeType, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task IsValidAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // long length = 0; + // string? mimeType = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.IsValidAsync( + // containerId, + // fileName, + // length, + // mimeType, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SaveAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // Stream stream = null; + // string? mimeType = null; + // Guid? parentId = null; + // bool ignoreCheck = false; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.SaveAsync( + // container, + // fileName, + // stream, + // mimeType, + // parentId, + // ignoreCheck, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SaveAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string fileName = null; + // byte[] bytes = null; + // string? mimeType = null; + // Guid? parentId = null; + // bool ignoreCheck = false; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.SaveAsync( + // container, + // fileName, + // bytes, + // mimeType, + // parentId, + // ignoreCheck, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SaveAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // Stream stream = null; + // string? mimeType = null; + // Guid? parentId = null; + // bool ignoreCheck = false; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.SaveAsync( + // containerId, + // fileName, + // stream, + // mimeType, + // parentId, + // ignoreCheck, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SaveAsync_StateUnderTest_ExpectedBehavior3() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string fileName = null; + // byte[] bytes = null; + // string? mimeType = null; + // Guid? parentId = null; + // bool ignoreCheck = false; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.SaveAsync( + // containerId, + // fileName, + // bytes, + // mimeType, + // parentId, + // ignoreCheck, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SetReadOnlyAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid fileId = default(global::System.Guid); + // bool isReadOnly = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.SetReadOnlyAsync( + // fileId, + // isReadOnly, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SetReadOnlyAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // bool isReadOnly = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.SetReadOnlyAsync( + // containerId, + // fileId, + // isReadOnly, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SetTagsAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid fileId = default(global::System.Guid); + // IEnumerable tags = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.SetTagsAsync( + // fileId, + // tags, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task SetTagsAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // IEnumerable tags = null; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.SetTagsAsync( + // containerId, + // fileId, + // tags, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task UnarchiveAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid fileId = default(global::System.Guid); + // string targetFileName = null; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.UnarchiveAsync( + // containerId, + // fileId, + // targetFileName, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task UnarchiveAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // Guid fileId = default(global::System.Guid); + // string targetFileName = null; + // Guid? targetParentId = null; + // bool overrideExisting = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // await manager.UnarchiveAsync( + // container, + // fileId, + // targetFileName, + // targetParentId, + // overrideExisting, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFilesAsync_StateUnderTest_ExpectedBehavior() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // string container = null; + // string directoryName = null; + // Guid? parentId = null; + // bool includeSubDirectory = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFilesAsync( + // container, + // directoryName, + // parentId, + // includeSubDirectory, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFilesAsync_StateUnderTest_ExpectedBehavior1() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // string directoryName = null; + // Guid? parentId = null; + // bool includeSubDirectory = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFilesAsync( + // containerId, + // directoryName, + // parentId, + // includeSubDirectory, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} + + //[Fact] + //public async Task GetFilesAsync_StateUnderTest_ExpectedBehavior2() + //{ + // // Arrange + // var manager = new FileManager(TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO, TODO); + // Guid containerId = default(global::System.Guid); + // Guid directoryId = default(global::System.Guid); + // bool includeSubDirectory = false; + // CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); + + // // Act + // var result = await manager.GetFilesAsync( + // containerId, + // directoryId, + // includeSubDirectory, + // cancellationToken); + + // // Assert + // Assert.True(false); + //} +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xml b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xsd b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xsd new file mode 100644 index 0000000..ffa6fc4 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.abppkg.json b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.abppkg.json new file mode 100644 index 0000000..a686451 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.abppkg.json @@ -0,0 +1,3 @@ +{ + "role": "lib.test" +} \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.csproj b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.csproj new file mode 100644 index 0000000..96b119f --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.Domain.Tests/Passingwind.Abp.FileManagement.Domain.Tests.csproj @@ -0,0 +1,16 @@ + + + + + + net7.0 + enable + Passingwind.Abp.FileManagement + + + + + + + + diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestBase.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestBase.cs new file mode 100644 index 0000000..71d24e8 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestBase.cs @@ -0,0 +1,9 @@ +namespace Passingwind.Abp.FileManagement.EntityFrameworkCore; + +/* This class can be used as a base class for EF Core integration tests, + * while SampleRepository_Tests uses a different approach. + */ +public abstract class FileManagementEntityFrameworkCoreTestBase : FileManagementTestBase +{ + +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestModule.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestModule.cs new file mode 100644 index 0000000..733d1af --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/FileManagementEntityFrameworkCoreTestModule.cs @@ -0,0 +1,45 @@ +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.Sqlite; +using Volo.Abp.Modularity; +using Volo.Abp.Uow; + +namespace Passingwind.Abp.FileManagement.EntityFrameworkCore; + +[DependsOn( + typeof(FileManagementTestBaseModule), + typeof(FileManagementEntityFrameworkCoreModule), + typeof(AbpEntityFrameworkCoreSqliteModule) + )] +public class FileManagementEntityFrameworkCoreTestModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAlwaysDisableUnitOfWorkTransaction(); + + var sqliteConnection = CreateDatabaseAndGetConnection(); + + Configure(options => + { + options.Configure(abpDbContextConfigurationContext => + { + abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection); + }); + }); + } + + private static SqliteConnection CreateDatabaseAndGetConnection() + { + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + + new FileManagementDbContext( + new DbContextOptionsBuilder().UseSqlite(connection).Options + ).GetService().CreateTables(); + + return connection; + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs new file mode 100644 index 0000000..4a687cb --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepository_Tests.cs @@ -0,0 +1,11 @@ +using Passingwind.Abp.FileManagement.Samples; + +namespace Passingwind.Abp.FileManagement.EntityFrameworkCore.Samples; + +public class SampleRepository_Tests : SampleRepository_Tests +{ + /* Don't write custom repository tests here, instead write to + * the base class. + * One exception can be some specific tests related to EF core. + */ +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xml b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xsd b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xsd new file mode 100644 index 0000000..ffa6fc4 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.abppkg.json b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.abppkg.json new file mode 100644 index 0000000..a686451 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.abppkg.json @@ -0,0 +1,3 @@ +{ + "role": "lib.test" +} \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.csproj b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.csproj new file mode 100644 index 0000000..1ba7a1c --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests/Passingwind.Abp.FileManagement.EntityFrameworkCore.Tests.csproj @@ -0,0 +1,19 @@ + + + + + + net7.0 + enable + Passingwind.Abp.FileManagement + + + + + + + + + + + diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ClientDemoService.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ClientDemoService.cs new file mode 100644 index 0000000..254d22a --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ClientDemoService.cs @@ -0,0 +1,153 @@ +//using System; +//using System.Net.Http; +//using System.Threading.Tasks; +//using IdentityModel.Client; +//using Microsoft.Extensions.Configuration; +//using Passingwind.Abp.FileManagement.Samples; +//using Volo.Abp.DependencyInjection; +//using Volo.Abp.IdentityModel; + +//namespace Passingwind.Abp.FileManagement; + +//public class ClientDemoService : ITransientDependency +//{ +// private readonly ISampleAppService _sampleAppService; +// private readonly IIdentityModelAuthenticationService _authenticationService; +// private readonly IConfiguration _configuration; + +// public ClientDemoService( +// ISampleAppService sampleAppService, +// IIdentityModelAuthenticationService authenticationService, +// IConfiguration configuration) +// { +// _sampleAppService = sampleAppService; +// _authenticationService = authenticationService; +// _configuration = configuration; +// } + +// public async Task RunAsync() +// { +// await TestWithDynamicProxiesAsync(); +// await TestWithHttpClientAndIdentityModelAuthenticationServiceAsync(); +// await TestAllManuallyAsync(); +// } + +// /* Shows how to perform an HTTP request to the API using ABP's dynamic c# proxy +// * feature. It is just simple as calling a local service method. +// * Authorization and HTTP request details are handled by the ABP framework. +// */ +// private async Task TestWithDynamicProxiesAsync() +// { +// Console.WriteLine(); +// Console.WriteLine($"***** {nameof(TestWithDynamicProxiesAsync)} *****"); + +// var result = await _sampleAppService.GetAsync(); +// Console.WriteLine("Result: " + result.Value); + +// result = await _sampleAppService.GetAuthorizedAsync(); +// Console.WriteLine("Result (authorized): " + result.Value); +// } + +// /* Shows how to use HttpClient to perform a request to the HTTP API. +// * It uses ABP's IIdentityModelAuthenticationService to simplify obtaining access tokens. +// */ +// private async Task TestWithHttpClientAndIdentityModelAuthenticationServiceAsync() +// { +// Console.WriteLine(); +// Console.WriteLine($"***** {nameof(TestWithHttpClientAndIdentityModelAuthenticationServiceAsync)} *****"); + +// //Get access token using ABP's IIdentityModelAuthenticationService + +// var accessToken = await _authenticationService.GetAccessTokenAsync( +// new IdentityClientConfiguration( +// _configuration["IdentityClients:Default:Authority"], +// _configuration["IdentityClients:Default:Scope"], +// _configuration["IdentityClients:Default:ClientId"], +// _configuration["IdentityClients:Default:ClientSecret"], +// _configuration["IdentityClients:Default:GrantType"], +// _configuration["IdentityClients:Default:UserName"], +// _configuration["IdentityClients:Default:UserPassword"] +// ) +// ); + +// //Perform the actual HTTP request + +// using (var httpClient = new HttpClient()) +// { +// httpClient.SetBearerToken(accessToken); + +// var url = _configuration["RemoteServices:FileManagement:BaseUrl"] + +// "api/FileManagement/sample/authorized"; + +// var responseMessage = await httpClient.GetAsync(url); +// if (responseMessage.IsSuccessStatusCode) +// { +// var responseString = await responseMessage.Content.ReadAsStringAsync(); +// Console.WriteLine("Result: " + responseString); +// } +// else +// { +// throw new Exception("Remote server returns error code: " + responseMessage.StatusCode); +// } +// } +// } + +// /* Shows how to use HttpClient to perform a request to the HTTP API. +// */ +// private async Task TestAllManuallyAsync() +// { +// Console.WriteLine(); +// Console.WriteLine($"***** {nameof(TestAllManuallyAsync)} *****"); + +// //Obtain access token from the IDS4 server + +// // discover endpoints from metadata +// var client = new HttpClient(); +// var disco = await client.GetDiscoveryDocumentAsync(_configuration["IdentityClients:Default:Authority"]); +// if (disco.IsError) +// { +// Console.WriteLine(disco.Error); +// return; +// } + +// // request token +// var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest +// { +// Address = disco.TokenEndpoint, +// ClientId = _configuration["IdentityClients:Default:ClientId"], +// ClientSecret = _configuration["IdentityClients:Default:ClientSecret"], +// UserName = _configuration["IdentityClients:Default:UserName"], +// Password = _configuration["IdentityClients:Default:UserPassword"], +// Scope = _configuration["IdentityClients:Default:Scope"] +// }); + +// if (tokenResponse.IsError) +// { +// Console.WriteLine(tokenResponse.Error); +// return; +// } + +// Console.WriteLine(tokenResponse.Json); + +// //Perform the actual HTTP request + +// using (var httpClient = new HttpClient()) +// { +// httpClient.SetBearerToken(tokenResponse.AccessToken); + +// var url = _configuration["RemoteServices:FileManagement:BaseUrl"] + +// "api/FileManagement/sample/authorized"; + +// var responseMessage = await httpClient.GetAsync(url); +// if (responseMessage.IsSuccessStatusCode) +// { +// var responseString = await responseMessage.Content.ReadAsStringAsync(); +// Console.WriteLine("Result: " + responseString); +// } +// else +// { +// throw new Exception("Remote server returns error code: " + responseMessage.StatusCode); +// } +// } +// } +//} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ConsoleTestAppHostedService.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ConsoleTestAppHostedService.cs new file mode 100644 index 0000000..a79431b --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/ConsoleTestAppHostedService.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Hosting; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; + +namespace Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp; + +public class ConsoleTestAppHostedService : IHostedService +{ + private readonly IConfiguration _configuration; + + public ConsoleTestAppHostedService(IConfiguration configuration) + { + _configuration = configuration; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + using (var application = await AbpApplicationFactory.CreateAsync(options => + { + options.Services.ReplaceConfiguration(_configuration); + options.UseAutofac(); + })) + { + await application.InitializeAsync(); + + //var demo = application.ServiceProvider.GetRequiredService(); + //await demo.RunAsync(); + + await application.ShutdownAsync(); + } + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/FileManagementConsoleApiClientModule.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/FileManagementConsoleApiClientModule.cs new file mode 100644 index 0000000..0358761 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/FileManagementConsoleApiClientModule.cs @@ -0,0 +1,15 @@ +using Volo.Abp.Autofac; +using Volo.Abp.Http.Client.IdentityModel; +using Volo.Abp.Modularity; + +namespace Passingwind.Abp.FileManagement; + +[DependsOn( + typeof(AbpAutofacModule), + typeof(FileManagementHttpApiClientModule), + typeof(AbpHttpClientIdentityModelModule) + )] +public class FileManagementConsoleApiClientModule : AbpModule +{ + +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.abppkg.json b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.abppkg.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.abppkg.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.csproj b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.csproj new file mode 100644 index 0000000..3a58d32 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp.csproj @@ -0,0 +1,33 @@ + + + + Exe + net7.0 + enable + Passingwind.Abp.FileManagement + + + + + + + + + + + + PreserveNewest + Always + + + + PreserveNewest + Always + + + + + + + + diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Program.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Program.cs new file mode 100644 index 0000000..2567a16 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/Program.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp; + +class Program +{ + static async Task Main(string[] args) + { + await CreateHostBuilder(args).RunConsoleAsync(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .AddAppSettingsSecretsJson() + .ConfigureServices((hostContext, services) => + { + services.AddHostedService(); + }); +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.json b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.json new file mode 100644 index 0000000..51ab1bf --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.json @@ -0,0 +1,21 @@ +{ + "RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:44323/" + }, + "FileManagement": { + "BaseUrl": "https://localhost:44358/" + } + }, + "IdentityClients": { + "Default": { + "GrantType": "password", + "ClientId": "FileManagement_App", + "ClientSecret": "1q2w3e*", + "UserName": "admin", + "UserPassword": "1q2w3E*", + "Authority": "https://localhost:44323/", + "Scope": "FileManagement" + } + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.secrets.json b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.secrets.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.HttpApi.Client.ConsoleTestApp/appsettings.secrets.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xml b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xsd b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xsd new file mode 100644 index 0000000..ffa6fc4 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestBase.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestBase.cs new file mode 100644 index 0000000..12eeb97 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestBase.cs @@ -0,0 +1,9 @@ +namespace Passingwind.Abp.FileManagement.MongoDB; + +/* This class can be used as a base class for MongoDB integration tests, + * while SampleRepository_Tests uses a different approach. + */ +public abstract class FileManagementMongoDbTestBase : FileManagementTestBase +{ + +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestModule.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestModule.cs new file mode 100644 index 0000000..5978f4b --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/FileManagementMongoDbTestModule.cs @@ -0,0 +1,21 @@ +using System; +using Volo.Abp.Data; +using Volo.Abp.Modularity; +using Volo.Abp.Uow; + +namespace Passingwind.Abp.FileManagement.MongoDB; + +[DependsOn( + typeof(FileManagementTestBaseModule), + typeof(FileManagementMongoDbModule) + )] +public class FileManagementMongoDbTestModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.ConnectionStrings.Default = MongoDbFixture.GetRandomConnectionString(); + }); + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoDbFixture.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoDbFixture.cs new file mode 100644 index 0000000..77fe9d7 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoDbFixture.cs @@ -0,0 +1,34 @@ +using System; +using EphemeralMongo; + +namespace Passingwind.Abp.FileManagement.MongoDB; + +public class MongoDbFixture : IDisposable +{ + public readonly static IMongoRunner MongoDbRunner; + + static MongoDbFixture() + { + MongoDbRunner = MongoRunner.Run(new MongoRunnerOptions + { + UseSingleNodeReplicaSet = true + }); + } + + public static string GetRandomConnectionString() + { + return GetConnectionString("Db_" + Guid.NewGuid().ToString("N")); + } + + public static string GetConnectionString(string databaseName) + { + var stringArray = MongoDbRunner.ConnectionString.Split('?'); + var connectionString = stringArray[0].EnsureEndsWith('/') + databaseName + "/?" + stringArray[1]; + return connectionString; + } + + public void Dispose() + { + MongoDbRunner?.Dispose(); + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoTestCollection.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoTestCollection.cs new file mode 100644 index 0000000..5b91269 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/MongoTestCollection.cs @@ -0,0 +1,9 @@ +using Xunit; + +namespace Passingwind.Abp.FileManagement.MongoDB; + +[CollectionDefinition(Name)] +public class MongoTestCollection : ICollectionFixture +{ + public const string Name = "MongoDB Collection"; +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/Samples/SampleRepository_Tests.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/Samples/SampleRepository_Tests.cs new file mode 100644 index 0000000..4ef7867 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/MongoDB/Samples/SampleRepository_Tests.cs @@ -0,0 +1,13 @@ +using Passingwind.Abp.FileManagement.Samples; +using Xunit; + +namespace Passingwind.Abp.FileManagement.MongoDB.Samples; + +[Collection(MongoTestCollection.Name)] +public class SampleRepository_Tests : SampleRepository_Tests +{ + /* Don't write custom repository tests here, instead write to + * the base class. + * One exception can be some specific tests related to MongoDB. + */ +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.abppkg.json b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.abppkg.json new file mode 100644 index 0000000..a686451 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.abppkg.json @@ -0,0 +1,3 @@ +{ + "role": "lib.test" +} \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.csproj b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.csproj new file mode 100644 index 0000000..bc12998 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.MongoDB.Tests/Passingwind.Abp.FileManagement.MongoDB.Tests.csproj @@ -0,0 +1,21 @@ + + + + + + net7.0 + enable + Passingwind.Abp.FileManagement + + + + + + + + + + + + + diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementDataSeedContributor.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementDataSeedContributor.cs new file mode 100644 index 0000000..16be143 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementDataSeedContributor.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; + +namespace Passingwind.Abp.FileManagement; + +public class FileManagementDataSeedContributor : IDataSeedContributor, ITransientDependency +{ + private readonly IGuidGenerator _guidGenerator; + private readonly ICurrentTenant _currentTenant; + private readonly IFileContainerRepository _fileContainerRepository; + private readonly IFileRepository _fileRepository; + + public FileManagementDataSeedContributor( + IGuidGenerator guidGenerator, ICurrentTenant currentTenant, IFileContainerRepository fileContainerRepository, IFileRepository fileRepository) + { + _guidGenerator = guidGenerator; + _currentTenant = currentTenant; + _fileContainerRepository = fileContainerRepository; + _fileRepository = fileRepository; + } + + public async Task SeedAsync(DataSeedContext context) + { + /* Instead of returning the Task.CompletedTask, you can insert your test data + * at this point! + */ + + using (_currentTenant.Change(context?.TenantId)) + { + // container + await _fileContainerRepository.InsertAsync(new FileContainer(Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f30"), "test-01", Files.FileAccessMode.Anonymous)); + await _fileContainerRepository.InsertAsync(new FileContainer(Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f31"), "test-02", Files.FileAccessMode.Authorized)); + await _fileContainerRepository.InsertAsync(new FileContainer(Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f32"), "test-03", Files.FileAccessMode.Private)); + + // files + await _fileRepository.InsertAsync(new FileItem(_guidGenerator.Create(), Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f30"), true, "dir01", "dir01")); + await _fileRepository.InsertAsync(new FileItem(_guidGenerator.Create(), Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f30"), true, "dir02", "dir02")); + + // await _fileRepository.InsertAsync(new FileItem(_guidGenerator.Create(), Guid.Parse("eaf86134-7148-490d-a08f-1a6abddf9f30"), false, "file01.txt", "file01.txt")); + } + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBase.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBase.cs new file mode 100644 index 0000000..b08f7f6 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBase.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Modularity; +using Volo.Abp.Uow; +using Volo.Abp.Testing; + +namespace Passingwind.Abp.FileManagement; + +/* All test classes are derived from this class, directly or indirectly. */ +public abstract class FileManagementTestBase : AbpIntegratedTest + where TStartupModule : IAbpModule +{ + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected virtual Task WithUnitOfWorkAsync(Func func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func action) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + await action(); + + await uow.CompleteAsync(); + } + } + } + + protected virtual Task WithUnitOfWorkAsync(Func> func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func> func) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + var result = await func(); + await uow.CompleteAsync(); + return result; + } + } + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBaseModule.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBaseModule.cs new file mode 100644 index 0000000..8746288 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FileManagementTestBaseModule.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Data; +using Volo.Abp.Modularity; +using Volo.Abp.Threading; + +namespace Passingwind.Abp.FileManagement; + +[DependsOn( + typeof(AbpAutofacModule), + typeof(AbpTestBaseModule), + typeof(AbpAuthorizationModule), + typeof(FileManagementDomainModule) + )] +public class FileManagementTestBaseModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAlwaysAllowAuthorization(); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + SeedTestData(context); + } + + private static void SeedTestData(ApplicationInitializationContext context) + { + AsyncHelper.RunSync(async () => + { + using (var scope = context.ServiceProvider.CreateScope()) + { + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync(); + } + }); + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xml b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xsd b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xsd new file mode 100644 index 0000000..ffa6fc4 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.abppkg.json b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.abppkg.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.abppkg.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.csproj b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.csproj new file mode 100644 index 0000000..91101d5 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Passingwind.Abp.FileManagement.TestBase.csproj @@ -0,0 +1,28 @@ + + + + + + net7.0 + enable + Passingwind.Abp.FileManagement + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Samples/SampleRepository_Tests.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Samples/SampleRepository_Tests.cs new file mode 100644 index 0000000..9b368c7 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Samples/SampleRepository_Tests.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Volo.Abp.Modularity; +using Xunit; + +namespace Passingwind.Abp.FileManagement.Samples; + +/* Write your custom repository tests like that, in this project, as abstract classes. + * Then inherit these abstract classes from EF Core & MongoDB test projects. + * In this way, both database providers are tests with the same set tests. + */ +public abstract class SampleRepository_Tests : FileManagementTestBase + where TStartupModule : IAbpModule +{ + //private readonly ISampleRepository _sampleRepository; + + protected SampleRepository_Tests() + { + //_sampleRepository = GetRequiredService(); + } + + [Fact] + public Task Method1Async() + { + return Task.CompletedTask; + } +} diff --git a/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Security/FakeCurrentPrincipalAccessor.cs b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Security/FakeCurrentPrincipalAccessor.cs new file mode 100644 index 0000000..acbad15 --- /dev/null +++ b/modules/file-management/test/Passingwind.Abp.FileManagement.TestBase/Security/FakeCurrentPrincipalAccessor.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Security.Claims; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Security.Claims; + +namespace Passingwind.Abp.FileManagement.Security; + +[Dependency(ReplaceServices = true)] +public class FakeCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor +{ + protected override ClaimsPrincipal GetClaimsPrincipal() + { + return GetPrincipal(); + } + + private ClaimsPrincipal GetPrincipal() + { + return new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim(AbpClaimTypes.UserId, "2e701e62-0953-4dd3-910b-dc6cc93ccb0d"), + new Claim(AbpClaimTypes.UserName, "admin"), + new Claim(AbpClaimTypes.Email, "admin@abp.io") + } + ) + ); + } +}