From 8e87a03e5c03e572976953cce7ff32b656e9ce5c Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 8 Apr 2025 11:54:33 +0530 Subject: [PATCH 01/54] rewrite audit --- src/Directory.Packages.props | 5 ++- src/api/framework/Core/Audit/TrailDto.cs | 37 ------------------- .../Audit/AuditPublishedEventHandler.cs | 24 ------------ .../Auditing/Abstractions}/IAuditService.cs | 4 +- .../Abstractions/IAuditTrailDbContext.cs | 9 +++++ src/framework/Auditing/Auditing.csproj | 23 ++++++++++++ src/framework/Auditing/Dtos/TrailDto.cs | 16 ++++++++ .../Auditing/Enums}/TrailType.cs | 2 +- .../Auditing/Events}/AuditPublishedEvent.cs | 4 +- .../Events/AuditPublishedEventHandler.cs | 36 ++++++++++++++++++ .../Interceptors/AuditInterceptor.cs | 13 ++++--- .../Auditing/Mappings/TrailMapping.cs | 29 +++++++++++++++ .../Auditing/Models}/AuditTrail.cs | 2 +- .../Auditing/Services}/AuditService.cs | 8 ++-- .../framework/Core/Auth/Jwt/JwtOptions.cs | 0 .../framework/Core/Caching/CacheOptions.cs | 0 .../Core/Caching/CacheServiceExtensions.cs | 0 .../framework/Core/Caching/ICacheService.cs | 0 src/{api => }/framework/Core/Core.csproj | 6 --- .../framework/Core/Domain/AuditableEntity.cs | 0 .../framework/Core/Domain/BaseEntity.cs | 0 .../Core/Domain/Contracts/IAggregateRoot.cs | 0 .../Core/Domain/Contracts/IAuditable.cs | 0 .../Core/Domain/Contracts/IEntity.cs | 0 .../Core/Domain/Contracts/ISoftDeletable.cs | 0 .../Core/Domain/Events/DomainEvent.cs | 0 .../Core/Domain/Events/IDomainEvent.cs | 0 .../Core/Exceptions/CustomException.cs | 0 .../Core/Exceptions/ForbiddenException.cs | 0 .../framework/Core/Exceptions/FshException.cs | 0 .../Core/Exceptions/NotFoundException.cs | 0 .../Core/Exceptions/UnauthorizedException.cs | 0 .../Core/ExecutionContext}/ICurrentUser.cs | 2 +- src/{api => }/framework/Core/FshCore.cs | 0 .../CreateOrUpdateRoleCommand.cs | 0 .../CreateOrUpdateRoleValidator.cs | 0 .../UpdatePermissionsCommand.cs | 0 .../UpdatePermissionsValidator.cs | 0 .../Core/Identity/Roles/IRoleService.cs | 0 .../framework/Core/Identity/Roles/RoleDto.cs | 0 .../Generate/TokenGenerationCommand.cs | 1 - .../Features/Refresh/RefreshTokenCommand.cs | 0 .../Core/Identity/Tokens/ITokenService.cs | 0 .../Identity/Tokens/Models/TokenResponse.cs | 0 .../Abstractions/ICurrentUserInitializer.cs | 0 .../Users/Abstractions/IUserService.cs | 0 .../Core/Identity/Users/Dtos/UserDetail.cs | 0 .../Identity/Users/Dtos/UserRoleDetail.cs | 0 .../AssignUserRole/AssignUserRoleCommand.cs | 0 .../ChangePassword/ChangePasswordCommand.cs | 0 .../ChangePassword/ChangePasswordValidator.cs | 0 .../ForgotPassword/ForgotPasswordCommand.cs | 0 .../ForgotPassword/ForgotPasswordValidator.cs | 0 .../RegisterUser/RegisterUserCommand.cs | 0 .../RegisterUser/RegisterUserResponse.cs | 0 .../ResetPassword/ResetPasswordCommand.cs | 0 .../ResetPassword/ResetPasswordValidator.cs | 0 .../ToggleUserStatusCommand.cs | 0 .../Features/UpdateUser/UpdateUserCommand.cs | 0 .../framework/Core/Jobs/IJobService.cs | 0 .../framework/Core/Mail/IMailService.cs | 0 .../framework/Core/Mail/MailOptions.cs | 0 .../framework/Core/Mail/MailRequest.cs | 0 .../framework/Core/Origin/OriginOptions.cs | 0 .../framework/Core/Paging/BaseFilter.cs | 0 .../framework/Core/Paging/Extensions.cs | 0 src/{api => }/framework/Core/Paging/Filter.cs | 0 .../framework/Core/Paging/IPageRequest.cs | 0 .../framework/Core/Paging/IPagedList.cs | 0 .../framework/Core/Paging/PagedList.cs | 0 .../framework/Core/Paging/PaginationFilter.cs | 0 src/{api => }/framework/Core/Paging/Search.cs | 0 .../Core/Persistence/DatabaseOptions.cs | 0 .../Persistence/IConnectionStringValidator.cs | 0 .../Core/Persistence/IDbInitializer.cs | 0 .../framework/Core/Persistence/IRepository.cs | 0 .../EntitiesByBaseFilterSpec.cs | 0 .../EntitiesByPaginationFilterSpec.cs | 0 .../SpecificationBuilderExtensions.cs | 0 .../File/Features/FileUploadCommand.cs | 0 .../File/Features/FileUploadResponse.cs | 0 .../File/Features/FileUploadValidator.cs | 0 .../framework/Core/Storage/File/FileType.cs | 0 .../framework/Core/Storage/IStorageService.cs | 0 .../Tenant/Abstractions/ITenantService.cs | 0 .../Core/Tenant/Dtos/TenantDetail.cs | 0 .../ActivateTenant/ActivateTenantCommand.cs | 0 .../ActivateTenant/ActivateTenantHandler.cs | 0 .../ActivateTenant/ActivateTenantResponse.cs | 0 .../ActivateTenant/ActivateTenantValidator.cs | 0 .../CreateTenant/CreateTenantCommand.cs | 0 .../CreateTenant/CreateTenantHandler.cs | 0 .../CreateTenant/CreateTenantResponse.cs | 0 .../CreateTenant/CreateTenantValidator.cs | 0 .../DisableTenant/DisableTenantCommand.cs | 0 .../DisableTenant/DisableTenantHandler.cs | 0 .../DisableTenant/DisableTenantResponse.cs | 0 .../DisableTenant/DisableTenantValidator.cs | 0 .../GetTenantById/GetTenantByIdHandler.cs | 0 .../GetTenantById/GetTenantByIdQuery.cs | 0 .../Features/GetTenants/GetTenantsHandler.cs | 0 .../Features/GetTenants/GetTenantsQuery.cs | 0 .../UpgradeSubscriptionCommand.cs | 0 .../UpgradeSubscriptionHandler.cs | 0 .../UpgradeSubscriptionResponse.cs | 0 .../UpgradeSubscriptionValidator.cs | 0 src/framework/FSH.Framework.sln | 34 +++++++++++++++++ .../Auth/CurrentUserMiddleware.cs | 0 .../Auth/Jwt/ConfigureJwtBearerOptions.cs | 0 .../Infrastructure/Auth/Jwt/Extensions.cs | 0 .../Auth/Jwt/JwtAuthConstants.cs | 0 .../Auth/Policy/EndpointExtensions.cs | 0 .../PermissionAuthorizationRequirement.cs | 0 .../Policy/RequiredPermissionAttribute.cs | 0 ...quiredPermissionAuthorizationExtensions.cs | 0 .../RequiredPermissionAuthorizationHandler.cs | 0 .../Behaviours/ValidationBehavior.cs | 0 .../Caching/DistributedCacheService.cs | 0 .../Infrastructure/Caching/Extensions.cs | 0 .../Common/Extensions/EnumExtensions.cs | 0 .../Common/Extensions/RegexExtensions.cs | 0 .../Constants/QueryStringKeys.cs | 0 .../Infrastructure/Cors/CorsOptions.cs | 0 .../Infrastructure/Cors/Extensions.cs | 0 .../Exceptions/CustomExceptionHandler.cs | 0 .../framework/Infrastructure/Extensions.cs | 0 .../Infrastructure/FshInfrastructure.cs | 0 .../HealthChecks/HealthCheckEndpoint.cs | 0 .../HealthChecks/HealthCheckMiddleware.cs | 0 .../Endpoints/GetUserAuditTrailEndpoint.cs | 0 .../Infrastructure/Identity/Extensions.cs | 1 + .../Persistence/IdentityConfiguration.cs | 0 .../Identity/Persistence/IdentityDbContext.cs | 0 .../Persistence/IdentityDbInitializer.cs | 0 .../Identity/RoleClaims/FshRoleClaim.cs | 0 .../Endpoints/CreateOrUpdateRoleEndpoint.cs | 0 .../Roles/Endpoints/DeleteRoleEndpoint.cs | 0 .../Identity/Roles/Endpoints/Extensions.cs | 0 .../Roles/Endpoints/GetRoleEndpoint.cs | 0 .../Endpoints/GetRolePermissionsEndpoint.cs | 0 .../Roles/Endpoints/GetRolesEndpoint.cs | 0 .../UpdateRolePermissionsEndpoint.cs | 0 .../Infrastructure/Identity/Roles/FshRole.cs | 0 .../Identity/Roles/RoleService.cs | 2 +- .../Identity/Tokens/Endpoints/Extensions.cs | 0 .../Tokens/Endpoints/RefreshTokenEndpoint.cs | 0 .../Endpoints/TokenGenerationEndpoint.cs | 0 .../Identity/Tokens/TokenService.cs | 0 .../Endpoints/AssignRolesToUserEndpoint.cs | 0 .../Users/Endpoints/ChangePasswordEndpoint.cs | 0 .../Users/Endpoints/ConfirmEmailEndpoint.cs | 0 .../Users/Endpoints/DeleteUserEndpoint.cs | 0 .../Identity/Users/Endpoints/Extensions.cs | 0 .../Users/Endpoints/ForgotPasswordEndpoint.cs | 0 .../Users/Endpoints/GetUserEndpoint.cs | 0 .../Endpoints/GetUserPermissionsEndpoint.cs | 0 .../Users/Endpoints/GetUserProfileEndpoint.cs | 0 .../Users/Endpoints/GetUserRolesEndpoint.cs | 0 .../Users/Endpoints/GetUsersListEndpoint.cs | 0 .../Users/Endpoints/RegisterUserEndpoint.cs | 0 .../Users/Endpoints/ResetPasswordEndpoint.cs | 0 .../Endpoints/SelfRegisterUserEndpoint.cs | 0 .../Endpoints/ToggleUserStatusEndpoint.cs | 0 .../Users/Endpoints/UpdateUserEndpoint.cs | 0 .../Infrastructure/Identity/Users/FshUser.cs | 0 .../Users/Services/CurrentUserService.cs | 1 + .../Users/Services/UserService.Password.cs | 0 .../Users/Services/UserService.Permissions.cs | 0 .../Identity/Users/Services/UserService.cs | 0 .../Infrastructure/Infrastructure.csproj | 22 +---------- .../Infrastructure/Jobs/Extensions.cs | 0 .../Infrastructure/Jobs/FshJobActivator.cs | 0 .../Infrastructure/Jobs/FshJobFilter.cs | 0 ...HangfireCustomBasicAuthenticationFilter.cs | 0 .../Infrastructure/Jobs/HangfireOptions.cs | 0 .../Infrastructure/Jobs/HangfireService.cs | 0 .../Infrastructure/Jobs/LogJobFilter.cs | 0 .../Logging/Serilog/Extensions.cs | 0 .../Logging/Serilog/StaticLogger.cs | 0 .../Infrastructure/Mail/Extensions.cs | 0 .../Infrastructure/Mail/SmtpMailService.cs | 0 .../OpenApi/ConfigureSwaggerOptions.cs | 0 .../Infrastructure/OpenApi/Extensions.cs | 0 .../OpenApi/SwaggerDefaultValues.cs | 0 .../AppendGlobalQueryFilterExtension.cs | 0 .../Infrastructure/Persistence/DbProviders.cs | 0 .../Infrastructure/Persistence/Extensions.cs | 0 .../Persistence/FshDbContext.cs | 0 .../Services/ConnectionStringValidator.cs | 0 .../Infrastructure/RateLimit/Extensions.cs | 0 .../RateLimit/RateLimitOptions.cs | 0 .../SecurityHeaders/Extensions.cs | 0 .../SecurityHeaders/SecurityHeaderOptions.cs | 0 .../SecurityHeaders/SecurityHeaders.cs | 0 .../Infrastructure/Storage/Files/Extension.cs | 0 .../Storage/Files/LocalFileStorageService.cs | 0 .../Tenant/Abstractions/IFshTenantInfo.cs | 0 .../Endpoints/ActivateTenantEndpoint.cs | 0 .../Tenant/Endpoints/CreateTenantEndpoint.cs | 0 .../Tenant/Endpoints/DisableTenantEndpoint.cs | 0 .../Tenant/Endpoints/Extensions.cs | 0 .../Tenant/Endpoints/GetTenantByIdEndpoint.cs | 0 .../Tenant/Endpoints/GetTenantsEndpoint.cs | 0 .../Endpoints/UpgradeSubscriptionEndpoint.cs | 0 .../Infrastructure/Tenant/Extensions.cs | 0 .../Infrastructure/Tenant/FshTenantInfo.cs | 0 .../Tenant/Persistence/TenantDbContext.cs | 0 .../Tenant/Services/TenantService.cs | 0 src/pos/api/FSH.POS.sln | 14 +++++++ 209 files changed, 188 insertions(+), 107 deletions(-) delete mode 100644 src/api/framework/Core/Audit/TrailDto.cs delete mode 100644 src/api/framework/Infrastructure/Identity/Audit/AuditPublishedEventHandler.cs rename src/{api/framework/Core/Audit => framework/Auditing/Abstractions}/IAuditService.cs (51%) create mode 100644 src/framework/Auditing/Abstractions/IAuditTrailDbContext.cs create mode 100644 src/framework/Auditing/Auditing.csproj create mode 100644 src/framework/Auditing/Dtos/TrailDto.cs rename src/{api/framework/Core/Audit => framework/Auditing/Enums}/TrailType.cs (66%) rename src/{api/framework/Infrastructure/Identity/Audit => framework/Auditing/Events}/AuditPublishedEvent.cs (75%) create mode 100644 src/framework/Auditing/Events/AuditPublishedEventHandler.cs rename src/{api/framework/Infrastructure/Persistence => framework/Auditing}/Interceptors/AuditInterceptor.cs (94%) create mode 100644 src/framework/Auditing/Mappings/TrailMapping.cs rename src/{api/framework/Core/Audit => framework/Auditing/Models}/AuditTrail.cs (90%) rename src/{api/framework/Infrastructure/Identity/Audit => framework/Auditing/Services}/AuditService.cs (60%) rename src/{api => }/framework/Core/Auth/Jwt/JwtOptions.cs (100%) rename src/{api => }/framework/Core/Caching/CacheOptions.cs (100%) rename src/{api => }/framework/Core/Caching/CacheServiceExtensions.cs (100%) rename src/{api => }/framework/Core/Caching/ICacheService.cs (100%) rename src/{api => }/framework/Core/Core.csproj (74%) rename src/{api => }/framework/Core/Domain/AuditableEntity.cs (100%) rename src/{api => }/framework/Core/Domain/BaseEntity.cs (100%) rename src/{api => }/framework/Core/Domain/Contracts/IAggregateRoot.cs (100%) rename src/{api => }/framework/Core/Domain/Contracts/IAuditable.cs (100%) rename src/{api => }/framework/Core/Domain/Contracts/IEntity.cs (100%) rename src/{api => }/framework/Core/Domain/Contracts/ISoftDeletable.cs (100%) rename src/{api => }/framework/Core/Domain/Events/DomainEvent.cs (100%) rename src/{api => }/framework/Core/Domain/Events/IDomainEvent.cs (100%) rename src/{api => }/framework/Core/Exceptions/CustomException.cs (100%) rename src/{api => }/framework/Core/Exceptions/ForbiddenException.cs (100%) rename src/{api => }/framework/Core/Exceptions/FshException.cs (100%) rename src/{api => }/framework/Core/Exceptions/NotFoundException.cs (100%) rename src/{api => }/framework/Core/Exceptions/UnauthorizedException.cs (100%) rename src/{api/framework/Core/Identity/Users/Abstractions => framework/Core/ExecutionContext}/ICurrentUser.cs (82%) rename src/{api => }/framework/Core/FshCore.cs (100%) rename src/{api => }/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs (100%) rename src/{api => }/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs (100%) rename src/{api => }/framework/Core/Identity/Roles/IRoleService.cs (100%) rename src/{api => }/framework/Core/Identity/Roles/RoleDto.cs (100%) rename src/{api => }/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs (93%) rename src/{api => }/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Tokens/ITokenService.cs (100%) rename src/{api => }/framework/Core/Identity/Tokens/Models/TokenResponse.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Abstractions/IUserService.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Dtos/UserDetail.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Dtos/UserRoleDetail.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs (100%) rename src/{api => }/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs (100%) rename src/{api => }/framework/Core/Jobs/IJobService.cs (100%) rename src/{api => }/framework/Core/Mail/IMailService.cs (100%) rename src/{api => }/framework/Core/Mail/MailOptions.cs (100%) rename src/{api => }/framework/Core/Mail/MailRequest.cs (100%) rename src/{api => }/framework/Core/Origin/OriginOptions.cs (100%) rename src/{api => }/framework/Core/Paging/BaseFilter.cs (100%) rename src/{api => }/framework/Core/Paging/Extensions.cs (100%) rename src/{api => }/framework/Core/Paging/Filter.cs (100%) rename src/{api => }/framework/Core/Paging/IPageRequest.cs (100%) rename src/{api => }/framework/Core/Paging/IPagedList.cs (100%) rename src/{api => }/framework/Core/Paging/PagedList.cs (100%) rename src/{api => }/framework/Core/Paging/PaginationFilter.cs (100%) rename src/{api => }/framework/Core/Paging/Search.cs (100%) rename src/{api => }/framework/Core/Persistence/DatabaseOptions.cs (100%) rename src/{api => }/framework/Core/Persistence/IConnectionStringValidator.cs (100%) rename src/{api => }/framework/Core/Persistence/IDbInitializer.cs (100%) rename src/{api => }/framework/Core/Persistence/IRepository.cs (100%) rename src/{api => }/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs (100%) rename src/{api => }/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs (100%) rename src/{api => }/framework/Core/Specifications/SpecificationBuilderExtensions.cs (100%) rename src/{api => }/framework/Core/Storage/File/Features/FileUploadCommand.cs (100%) rename src/{api => }/framework/Core/Storage/File/Features/FileUploadResponse.cs (100%) rename src/{api => }/framework/Core/Storage/File/Features/FileUploadValidator.cs (100%) rename src/{api => }/framework/Core/Storage/File/FileType.cs (100%) rename src/{api => }/framework/Core/Storage/IStorageService.cs (100%) rename src/{api => }/framework/Core/Tenant/Abstractions/ITenantService.cs (100%) rename src/{api => }/framework/Core/Tenant/Dtos/TenantDetail.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs (100%) rename src/{api => }/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs (100%) create mode 100644 src/framework/FSH.Framework.sln rename src/{api => }/framework/Infrastructure/Auth/CurrentUserMiddleware.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Jwt/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs (100%) rename src/{api => }/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs (100%) rename src/{api => }/framework/Infrastructure/Behaviours/ValidationBehavior.cs (100%) rename src/{api => }/framework/Infrastructure/Caching/DistributedCacheService.cs (100%) rename src/{api => }/framework/Infrastructure/Caching/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Common/Extensions/EnumExtensions.cs (100%) rename src/{api => }/framework/Infrastructure/Common/Extensions/RegexExtensions.cs (100%) rename src/{api => }/framework/Infrastructure/Constants/QueryStringKeys.cs (100%) rename src/{api => }/framework/Infrastructure/Cors/CorsOptions.cs (100%) rename src/{api => }/framework/Infrastructure/Cors/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs (100%) rename src/{api => }/framework/Infrastructure/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/FshInfrastructure.cs (100%) rename src/{api => }/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Extensions.cs (98%) rename src/{api => }/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/FshRole.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Roles/RoleService.cs (98%) rename src/{api => }/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Tokens/TokenService.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/ConfirmEmailEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/DeleteUserEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/ForgotPasswordEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/GetUserEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/GetUserPermissionsEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/GetUserProfileEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/GetUsersListEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/RegisterUserEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/ResetPasswordEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/SelfRegisterUserEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/ToggleUserStatusEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Endpoints/UpdateUserEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/FshUser.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs (97%) rename src/{api => }/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs (100%) rename src/{api => }/framework/Infrastructure/Identity/Users/Services/UserService.cs (100%) rename src/{api => }/framework/Infrastructure/Infrastructure.csproj (75%) rename src/{api => }/framework/Infrastructure/Jobs/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Jobs/FshJobActivator.cs (100%) rename src/{api => }/framework/Infrastructure/Jobs/FshJobFilter.cs (100%) rename src/{api => }/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs (100%) rename src/{api => }/framework/Infrastructure/Jobs/HangfireOptions.cs (100%) rename src/{api => }/framework/Infrastructure/Jobs/HangfireService.cs (100%) rename src/{api => }/framework/Infrastructure/Jobs/LogJobFilter.cs (100%) rename src/{api => }/framework/Infrastructure/Logging/Serilog/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Logging/Serilog/StaticLogger.cs (100%) rename src/{api => }/framework/Infrastructure/Mail/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Mail/SmtpMailService.cs (100%) rename src/{api => }/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs (100%) rename src/{api => }/framework/Infrastructure/OpenApi/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs (100%) rename src/{api => }/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs (100%) rename src/{api => }/framework/Infrastructure/Persistence/DbProviders.cs (100%) rename src/{api => }/framework/Infrastructure/Persistence/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Persistence/FshDbContext.cs (100%) rename src/{api => }/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs (100%) rename src/{api => }/framework/Infrastructure/RateLimit/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/RateLimit/RateLimitOptions.cs (100%) rename src/{api => }/framework/Infrastructure/SecurityHeaders/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs (100%) rename src/{api => }/framework/Infrastructure/SecurityHeaders/SecurityHeaders.cs (100%) rename src/{api => }/framework/Infrastructure/Storage/Files/Extension.cs (100%) rename src/{api => }/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Endpoints/CreateTenantEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Endpoints/DisableTenantEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Endpoints/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Endpoints/GetTenantByIdEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Endpoints/GetTenantsEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Endpoints/UpgradeSubscriptionEndpoint.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Extensions.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/FshTenantInfo.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs (100%) rename src/{api => }/framework/Infrastructure/Tenant/Services/TenantService.cs (100%) create mode 100644 src/pos/api/FSH.POS.sln diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 7015fadba..35dedb554 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -26,6 +26,7 @@ + @@ -40,7 +41,7 @@ - + @@ -50,7 +51,7 @@ - + diff --git a/src/api/framework/Core/Audit/TrailDto.cs b/src/api/framework/Core/Audit/TrailDto.cs deleted file mode 100644 index 8268e4b17..000000000 --- a/src/api/framework/Core/Audit/TrailDto.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.ObjectModel; -using System.Text.Json; - -namespace FSH.Framework.Core.Audit; -public class TrailDto() -{ - public Guid Id { get; set; } - public DateTimeOffset DateTime { get; set; } - public Guid UserId { get; set; } - public Dictionary KeyValues { get; } = []; - public Dictionary OldValues { get; } = []; - public Dictionary NewValues { get; } = []; - public Collection ModifiedProperties { get; } = []; - public TrailType Type { get; set; } - public string? TableName { get; set; } - - private static readonly JsonSerializerOptions SerializerOptions = new() - { - WriteIndented = false, - }; - - public AuditTrail ToAuditTrail() - { - return new() - { - Id = Guid.NewGuid(), - UserId = UserId, - Operation = Type.ToString(), - Entity = TableName, - DateTime = DateTime, - PrimaryKey = JsonSerializer.Serialize(KeyValues, SerializerOptions), - PreviousValues = OldValues.Count == 0 ? null : JsonSerializer.Serialize(OldValues, SerializerOptions), - NewValues = NewValues.Count == 0 ? null : JsonSerializer.Serialize(NewValues, SerializerOptions), - ModifiedProperties = ModifiedProperties.Count == 0 ? null : JsonSerializer.Serialize(ModifiedProperties, SerializerOptions) - }; - } -} diff --git a/src/api/framework/Infrastructure/Identity/Audit/AuditPublishedEventHandler.cs b/src/api/framework/Infrastructure/Identity/Audit/AuditPublishedEventHandler.cs deleted file mode 100644 index cb255f82a..000000000 --- a/src/api/framework/Infrastructure/Identity/Audit/AuditPublishedEventHandler.cs +++ /dev/null @@ -1,24 +0,0 @@ -using FSH.Framework.Core.Audit; -using FSH.Framework.Infrastructure.Identity.Persistence; -using MediatR; -using Microsoft.Extensions.Logging; - -namespace FSH.Framework.Infrastructure.Identity.Audit; -public class AuditPublishedEventHandler(ILogger logger, IdentityDbContext context) : INotificationHandler -{ - public async Task Handle(AuditPublishedEvent notification, CancellationToken cancellationToken) - { - if (context == null) return; - logger.LogInformation("received audit trails"); - try - { - await context.Set().AddRangeAsync(notification.Trails!, default); - await context.SaveChangesAsync(default); - } - catch - { - logger.LogError("error while saving audit trail"); - } - return; - } -} diff --git a/src/api/framework/Core/Audit/IAuditService.cs b/src/framework/Auditing/Abstractions/IAuditService.cs similarity index 51% rename from src/api/framework/Core/Audit/IAuditService.cs rename to src/framework/Auditing/Abstractions/IAuditService.cs index 9c62f4d0d..f7fe84f49 100644 --- a/src/api/framework/Core/Audit/IAuditService.cs +++ b/src/framework/Auditing/Abstractions/IAuditService.cs @@ -1,4 +1,6 @@ -namespace FSH.Framework.Core.Audit; +using FSH.Framework.Auditing.Models; + +namespace FSH.Framework.Auditing.Abstractions; public interface IAuditService { Task> GetUserTrailsAsync(Guid userId); diff --git a/src/framework/Auditing/Abstractions/IAuditTrailDbContext.cs b/src/framework/Auditing/Abstractions/IAuditTrailDbContext.cs new file mode 100644 index 000000000..5532bbc89 --- /dev/null +++ b/src/framework/Auditing/Abstractions/IAuditTrailDbContext.cs @@ -0,0 +1,9 @@ +using FSH.Framework.Auditing.Models; +using Microsoft.EntityFrameworkCore; + +namespace FSH.Framework.Auditing.Abstractions; +public interface IAuditTrailDbContext +{ + DbSet AuditTrails { get; } + Task SaveChangesAsync(CancellationToken cancellationToken); +} diff --git a/src/framework/Auditing/Auditing.csproj b/src/framework/Auditing/Auditing.csproj new file mode 100644 index 000000000..cec8661b6 --- /dev/null +++ b/src/framework/Auditing/Auditing.csproj @@ -0,0 +1,23 @@ + + + FSH.Framework.Auditing + FSH.Framework.Auditing + + + net9.0 + enable + enable + + + + + + + + + + + + + + diff --git a/src/framework/Auditing/Dtos/TrailDto.cs b/src/framework/Auditing/Dtos/TrailDto.cs new file mode 100644 index 000000000..33b2d203a --- /dev/null +++ b/src/framework/Auditing/Dtos/TrailDto.cs @@ -0,0 +1,16 @@ +using System.Collections.ObjectModel; +using FSH.Framework.Auditing.Enums; + +namespace FSH.Framework.Auditing.Dtos; +public class TrailDto +{ + public Guid Id { get; set; } + public DateTimeOffset DateTime { get; set; } + public Guid UserId { get; set; } + public Dictionary KeyValues { get; } = []; + public Dictionary OldValues { get; } = []; + public Dictionary NewValues { get; } = []; + public Collection ModifiedProperties { get; } = []; + public TrailType Type { get; set; } + public string? TableName { get; set; } +} diff --git a/src/api/framework/Core/Audit/TrailType.cs b/src/framework/Auditing/Enums/TrailType.cs similarity index 66% rename from src/api/framework/Core/Audit/TrailType.cs rename to src/framework/Auditing/Enums/TrailType.cs index a98bfa29b..5c0d1a909 100644 --- a/src/api/framework/Core/Audit/TrailType.cs +++ b/src/framework/Auditing/Enums/TrailType.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Audit; +namespace FSH.Framework.Auditing.Enums; public enum TrailType { None = 0, diff --git a/src/api/framework/Infrastructure/Identity/Audit/AuditPublishedEvent.cs b/src/framework/Auditing/Events/AuditPublishedEvent.cs similarity index 75% rename from src/api/framework/Infrastructure/Identity/Audit/AuditPublishedEvent.cs rename to src/framework/Auditing/Events/AuditPublishedEvent.cs index 46587882d..8d0255670 100644 --- a/src/api/framework/Infrastructure/Identity/Audit/AuditPublishedEvent.cs +++ b/src/framework/Auditing/Events/AuditPublishedEvent.cs @@ -1,8 +1,8 @@ using System.Collections.ObjectModel; -using FSH.Framework.Core.Audit; +using FSH.Framework.Auditing.Models; using MediatR; -namespace FSH.Framework.Infrastructure.Identity.Audit; +namespace FSH.Framework.Auditing.Events; public class AuditPublishedEvent : INotification { public AuditPublishedEvent(Collection? trails) diff --git a/src/framework/Auditing/Events/AuditPublishedEventHandler.cs b/src/framework/Auditing/Events/AuditPublishedEventHandler.cs new file mode 100644 index 000000000..0e23cf482 --- /dev/null +++ b/src/framework/Auditing/Events/AuditPublishedEventHandler.cs @@ -0,0 +1,36 @@ +using FSH.Framework.Auditing.Abstractions; +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace FSH.Framework.Auditing.Events; + +public class AuditPublishedEventHandler( + ILogger logger, + IAuditTrailDbContext context) + : INotificationHandler +{ + public async Task Handle(AuditPublishedEvent notification, CancellationToken cancellationToken) + { + if (notification.Trails == null || notification.Trails.Count == 0) + { + logger.LogDebug("No audit trails to persist."); + return; + } + + try + { + await context.AuditTrails.AddRangeAsync(notification.Trails, cancellationToken); + await context.SaveChangesAsync(cancellationToken); + logger.LogInformation("Persisted {Count} audit trail(s).", notification.Trails.Count); + } + catch (DbUpdateException ex) + { + logger.LogError(ex, "Database update error while saving audit trails."); + } + catch (Exception ex) + { + logger.LogError(ex, "Unexpected error while saving audit trails."); + } + } +} diff --git a/src/api/framework/Infrastructure/Persistence/Interceptors/AuditInterceptor.cs b/src/framework/Auditing/Interceptors/AuditInterceptor.cs similarity index 94% rename from src/api/framework/Infrastructure/Persistence/Interceptors/AuditInterceptor.cs rename to src/framework/Auditing/Interceptors/AuditInterceptor.cs index 6c2d819ca..c8e501741 100644 --- a/src/api/framework/Infrastructure/Persistence/Interceptors/AuditInterceptor.cs +++ b/src/framework/Auditing/Interceptors/AuditInterceptor.cs @@ -1,15 +1,18 @@ using System.Collections.ObjectModel; -using FSH.Framework.Core.Audit; +using FSH.Framework.Auditing.Dtos; +using FSH.Framework.Auditing.Enums; +using FSH.Framework.Auditing.Events; +using FSH.Framework.Auditing.Mappings; +using FSH.Framework.Auditing.Models; using FSH.Framework.Core.Domain; using FSH.Framework.Core.Domain.Contracts; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Infrastructure.Identity.Audit; +using FSH.Framework.Core.ExecutionContext; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; -namespace FSH.Framework.Infrastructure.Persistence.Interceptors; +namespace FSH.Framework.Auditing.Interceptors; public class AuditInterceptor(ICurrentUser currentUser, TimeProvider timeProvider, IPublisher publisher) : SaveChangesInterceptor { @@ -125,7 +128,7 @@ public void UpdateEntities(DbContext? context) entry.Entity.LastModifiedBy = currentUser.GetUserId(); entry.Entity.LastModified = utcNow; } - if(entry.State is EntityState.Deleted && entry.Entity is ISoftDeletable softDelete) + if (entry.State is EntityState.Deleted && entry.Entity is ISoftDeletable softDelete) { softDelete.DeletedBy = currentUser.GetUserId(); softDelete.Deleted = utcNow; diff --git a/src/framework/Auditing/Mappings/TrailMapping.cs b/src/framework/Auditing/Mappings/TrailMapping.cs new file mode 100644 index 000000000..b7985ab64 --- /dev/null +++ b/src/framework/Auditing/Mappings/TrailMapping.cs @@ -0,0 +1,29 @@ +using System.Text.Json; +using FSH.Framework.Auditing.Dtos; +using FSH.Framework.Auditing.Models; + +namespace FSH.Framework.Auditing.Mappings; + +public static class TrailMapping +{ + private static readonly JsonSerializerOptions SerializerOptions = new() + { + WriteIndented = false, + }; + + public static AuditTrail ToAuditTrail(this TrailDto trail) + { + return new AuditTrail + { + Id = Guid.NewGuid(), + UserId = trail.UserId, + Operation = trail.Type.ToString(), + Entity = trail.TableName, + DateTime = trail.DateTime, + PrimaryKey = JsonSerializer.Serialize(trail.KeyValues, SerializerOptions), + PreviousValues = trail.OldValues.Count == 0 ? null : JsonSerializer.Serialize(trail.OldValues, SerializerOptions), + NewValues = trail.NewValues.Count == 0 ? null : JsonSerializer.Serialize(trail.NewValues, SerializerOptions), + ModifiedProperties = trail.ModifiedProperties.Count == 0 ? null : JsonSerializer.Serialize(trail.ModifiedProperties, SerializerOptions) + }; + } +} diff --git a/src/api/framework/Core/Audit/AuditTrail.cs b/src/framework/Auditing/Models/AuditTrail.cs similarity index 90% rename from src/api/framework/Core/Audit/AuditTrail.cs rename to src/framework/Auditing/Models/AuditTrail.cs index 97448ac39..99e8bde1c 100644 --- a/src/api/framework/Core/Audit/AuditTrail.cs +++ b/src/framework/Auditing/Models/AuditTrail.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Audit; +namespace FSH.Framework.Auditing.Models; public class AuditTrail { public Guid Id { get; set; } diff --git a/src/api/framework/Infrastructure/Identity/Audit/AuditService.cs b/src/framework/Auditing/Services/AuditService.cs similarity index 60% rename from src/api/framework/Infrastructure/Identity/Audit/AuditService.cs rename to src/framework/Auditing/Services/AuditService.cs index 823cb7957..018ec962a 100644 --- a/src/api/framework/Infrastructure/Identity/Audit/AuditService.cs +++ b/src/framework/Auditing/Services/AuditService.cs @@ -1,9 +1,9 @@ -using FSH.Framework.Core.Audit; -using FSH.Framework.Infrastructure.Identity.Persistence; +using FSH.Framework.Auditing.Abstractions; +using FSH.Framework.Auditing.Models; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Infrastructure.Identity.Audit; -public class AuditService(IdentityDbContext context) : IAuditService +namespace FSH.Framework.Auditing.Services; +public class AuditService(IAuditTrailDbContext context) : IAuditService { public async Task> GetUserTrailsAsync(Guid userId) { diff --git a/src/api/framework/Core/Auth/Jwt/JwtOptions.cs b/src/framework/Core/Auth/Jwt/JwtOptions.cs similarity index 100% rename from src/api/framework/Core/Auth/Jwt/JwtOptions.cs rename to src/framework/Core/Auth/Jwt/JwtOptions.cs diff --git a/src/api/framework/Core/Caching/CacheOptions.cs b/src/framework/Core/Caching/CacheOptions.cs similarity index 100% rename from src/api/framework/Core/Caching/CacheOptions.cs rename to src/framework/Core/Caching/CacheOptions.cs diff --git a/src/api/framework/Core/Caching/CacheServiceExtensions.cs b/src/framework/Core/Caching/CacheServiceExtensions.cs similarity index 100% rename from src/api/framework/Core/Caching/CacheServiceExtensions.cs rename to src/framework/Core/Caching/CacheServiceExtensions.cs diff --git a/src/api/framework/Core/Caching/ICacheService.cs b/src/framework/Core/Caching/ICacheService.cs similarity index 100% rename from src/api/framework/Core/Caching/ICacheService.cs rename to src/framework/Core/Caching/ICacheService.cs diff --git a/src/api/framework/Core/Core.csproj b/src/framework/Core/Core.csproj similarity index 74% rename from src/api/framework/Core/Core.csproj rename to src/framework/Core/Core.csproj index 13d0f1dbc..aa4ae8c10 100644 --- a/src/api/framework/Core/Core.csproj +++ b/src/framework/Core/Core.csproj @@ -10,10 +10,4 @@ - - - - - - diff --git a/src/api/framework/Core/Domain/AuditableEntity.cs b/src/framework/Core/Domain/AuditableEntity.cs similarity index 100% rename from src/api/framework/Core/Domain/AuditableEntity.cs rename to src/framework/Core/Domain/AuditableEntity.cs diff --git a/src/api/framework/Core/Domain/BaseEntity.cs b/src/framework/Core/Domain/BaseEntity.cs similarity index 100% rename from src/api/framework/Core/Domain/BaseEntity.cs rename to src/framework/Core/Domain/BaseEntity.cs diff --git a/src/api/framework/Core/Domain/Contracts/IAggregateRoot.cs b/src/framework/Core/Domain/Contracts/IAggregateRoot.cs similarity index 100% rename from src/api/framework/Core/Domain/Contracts/IAggregateRoot.cs rename to src/framework/Core/Domain/Contracts/IAggregateRoot.cs diff --git a/src/api/framework/Core/Domain/Contracts/IAuditable.cs b/src/framework/Core/Domain/Contracts/IAuditable.cs similarity index 100% rename from src/api/framework/Core/Domain/Contracts/IAuditable.cs rename to src/framework/Core/Domain/Contracts/IAuditable.cs diff --git a/src/api/framework/Core/Domain/Contracts/IEntity.cs b/src/framework/Core/Domain/Contracts/IEntity.cs similarity index 100% rename from src/api/framework/Core/Domain/Contracts/IEntity.cs rename to src/framework/Core/Domain/Contracts/IEntity.cs diff --git a/src/api/framework/Core/Domain/Contracts/ISoftDeletable.cs b/src/framework/Core/Domain/Contracts/ISoftDeletable.cs similarity index 100% rename from src/api/framework/Core/Domain/Contracts/ISoftDeletable.cs rename to src/framework/Core/Domain/Contracts/ISoftDeletable.cs diff --git a/src/api/framework/Core/Domain/Events/DomainEvent.cs b/src/framework/Core/Domain/Events/DomainEvent.cs similarity index 100% rename from src/api/framework/Core/Domain/Events/DomainEvent.cs rename to src/framework/Core/Domain/Events/DomainEvent.cs diff --git a/src/api/framework/Core/Domain/Events/IDomainEvent.cs b/src/framework/Core/Domain/Events/IDomainEvent.cs similarity index 100% rename from src/api/framework/Core/Domain/Events/IDomainEvent.cs rename to src/framework/Core/Domain/Events/IDomainEvent.cs diff --git a/src/api/framework/Core/Exceptions/CustomException.cs b/src/framework/Core/Exceptions/CustomException.cs similarity index 100% rename from src/api/framework/Core/Exceptions/CustomException.cs rename to src/framework/Core/Exceptions/CustomException.cs diff --git a/src/api/framework/Core/Exceptions/ForbiddenException.cs b/src/framework/Core/Exceptions/ForbiddenException.cs similarity index 100% rename from src/api/framework/Core/Exceptions/ForbiddenException.cs rename to src/framework/Core/Exceptions/ForbiddenException.cs diff --git a/src/api/framework/Core/Exceptions/FshException.cs b/src/framework/Core/Exceptions/FshException.cs similarity index 100% rename from src/api/framework/Core/Exceptions/FshException.cs rename to src/framework/Core/Exceptions/FshException.cs diff --git a/src/api/framework/Core/Exceptions/NotFoundException.cs b/src/framework/Core/Exceptions/NotFoundException.cs similarity index 100% rename from src/api/framework/Core/Exceptions/NotFoundException.cs rename to src/framework/Core/Exceptions/NotFoundException.cs diff --git a/src/api/framework/Core/Exceptions/UnauthorizedException.cs b/src/framework/Core/Exceptions/UnauthorizedException.cs similarity index 100% rename from src/api/framework/Core/Exceptions/UnauthorizedException.cs rename to src/framework/Core/Exceptions/UnauthorizedException.cs diff --git a/src/api/framework/Core/Identity/Users/Abstractions/ICurrentUser.cs b/src/framework/Core/ExecutionContext/ICurrentUser.cs similarity index 82% rename from src/api/framework/Core/Identity/Users/Abstractions/ICurrentUser.cs rename to src/framework/Core/ExecutionContext/ICurrentUser.cs index aa5314b00..2e8d6b91a 100644 --- a/src/api/framework/Core/Identity/Users/Abstractions/ICurrentUser.cs +++ b/src/framework/Core/ExecutionContext/ICurrentUser.cs @@ -1,6 +1,6 @@ using System.Security.Claims; -namespace FSH.Framework.Core.Identity.Users.Abstractions; +namespace FSH.Framework.Core.ExecutionContext; public interface ICurrentUser { string? Name { get; } diff --git a/src/api/framework/Core/FshCore.cs b/src/framework/Core/FshCore.cs similarity index 100% rename from src/api/framework/Core/FshCore.cs rename to src/framework/Core/FshCore.cs diff --git a/src/api/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs b/src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs rename to src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs diff --git a/src/api/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs b/src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs similarity index 100% rename from src/api/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs rename to src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs diff --git a/src/api/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs rename to src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs diff --git a/src/api/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs b/src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs similarity index 100% rename from src/api/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs rename to src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs diff --git a/src/api/framework/Core/Identity/Roles/IRoleService.cs b/src/framework/Core/Identity/Roles/IRoleService.cs similarity index 100% rename from src/api/framework/Core/Identity/Roles/IRoleService.cs rename to src/framework/Core/Identity/Roles/IRoleService.cs diff --git a/src/api/framework/Core/Identity/Roles/RoleDto.cs b/src/framework/Core/Identity/Roles/RoleDto.cs similarity index 100% rename from src/api/framework/Core/Identity/Roles/RoleDto.cs rename to src/framework/Core/Identity/Roles/RoleDto.cs diff --git a/src/api/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs b/src/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs similarity index 93% rename from src/api/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs rename to src/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs index dccc1e15d..ee747c7ba 100644 --- a/src/api/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs +++ b/src/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs @@ -1,6 +1,5 @@ using System.ComponentModel; using FluentValidation; -using FSH.Starter.Shared.Authorization; namespace FSH.Framework.Core.Identity.Tokens.Features.Generate; public record TokenGenerationCommand( diff --git a/src/api/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs b/src/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs rename to src/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs diff --git a/src/api/framework/Core/Identity/Tokens/ITokenService.cs b/src/framework/Core/Identity/Tokens/ITokenService.cs similarity index 100% rename from src/api/framework/Core/Identity/Tokens/ITokenService.cs rename to src/framework/Core/Identity/Tokens/ITokenService.cs diff --git a/src/api/framework/Core/Identity/Tokens/Models/TokenResponse.cs b/src/framework/Core/Identity/Tokens/Models/TokenResponse.cs similarity index 100% rename from src/api/framework/Core/Identity/Tokens/Models/TokenResponse.cs rename to src/framework/Core/Identity/Tokens/Models/TokenResponse.cs diff --git a/src/api/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs b/src/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs rename to src/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs diff --git a/src/api/framework/Core/Identity/Users/Abstractions/IUserService.cs b/src/framework/Core/Identity/Users/Abstractions/IUserService.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Abstractions/IUserService.cs rename to src/framework/Core/Identity/Users/Abstractions/IUserService.cs diff --git a/src/api/framework/Core/Identity/Users/Dtos/UserDetail.cs b/src/framework/Core/Identity/Users/Dtos/UserDetail.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Dtos/UserDetail.cs rename to src/framework/Core/Identity/Users/Dtos/UserDetail.cs diff --git a/src/api/framework/Core/Identity/Users/Dtos/UserRoleDetail.cs b/src/framework/Core/Identity/Users/Dtos/UserRoleDetail.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Dtos/UserRoleDetail.cs rename to src/framework/Core/Identity/Users/Dtos/UserRoleDetail.cs diff --git a/src/api/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs b/src/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs rename to src/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs diff --git a/src/api/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs b/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs rename to src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs diff --git a/src/api/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs b/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs rename to src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs diff --git a/src/api/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs b/src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs rename to src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs diff --git a/src/api/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs b/src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs rename to src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs diff --git a/src/api/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs b/src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs rename to src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs diff --git a/src/api/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs b/src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs rename to src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs diff --git a/src/api/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs b/src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs rename to src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs diff --git a/src/api/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs b/src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs rename to src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs diff --git a/src/api/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs b/src/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs rename to src/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs diff --git a/src/api/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs b/src/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs similarity index 100% rename from src/api/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs rename to src/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs diff --git a/src/api/framework/Core/Jobs/IJobService.cs b/src/framework/Core/Jobs/IJobService.cs similarity index 100% rename from src/api/framework/Core/Jobs/IJobService.cs rename to src/framework/Core/Jobs/IJobService.cs diff --git a/src/api/framework/Core/Mail/IMailService.cs b/src/framework/Core/Mail/IMailService.cs similarity index 100% rename from src/api/framework/Core/Mail/IMailService.cs rename to src/framework/Core/Mail/IMailService.cs diff --git a/src/api/framework/Core/Mail/MailOptions.cs b/src/framework/Core/Mail/MailOptions.cs similarity index 100% rename from src/api/framework/Core/Mail/MailOptions.cs rename to src/framework/Core/Mail/MailOptions.cs diff --git a/src/api/framework/Core/Mail/MailRequest.cs b/src/framework/Core/Mail/MailRequest.cs similarity index 100% rename from src/api/framework/Core/Mail/MailRequest.cs rename to src/framework/Core/Mail/MailRequest.cs diff --git a/src/api/framework/Core/Origin/OriginOptions.cs b/src/framework/Core/Origin/OriginOptions.cs similarity index 100% rename from src/api/framework/Core/Origin/OriginOptions.cs rename to src/framework/Core/Origin/OriginOptions.cs diff --git a/src/api/framework/Core/Paging/BaseFilter.cs b/src/framework/Core/Paging/BaseFilter.cs similarity index 100% rename from src/api/framework/Core/Paging/BaseFilter.cs rename to src/framework/Core/Paging/BaseFilter.cs diff --git a/src/api/framework/Core/Paging/Extensions.cs b/src/framework/Core/Paging/Extensions.cs similarity index 100% rename from src/api/framework/Core/Paging/Extensions.cs rename to src/framework/Core/Paging/Extensions.cs diff --git a/src/api/framework/Core/Paging/Filter.cs b/src/framework/Core/Paging/Filter.cs similarity index 100% rename from src/api/framework/Core/Paging/Filter.cs rename to src/framework/Core/Paging/Filter.cs diff --git a/src/api/framework/Core/Paging/IPageRequest.cs b/src/framework/Core/Paging/IPageRequest.cs similarity index 100% rename from src/api/framework/Core/Paging/IPageRequest.cs rename to src/framework/Core/Paging/IPageRequest.cs diff --git a/src/api/framework/Core/Paging/IPagedList.cs b/src/framework/Core/Paging/IPagedList.cs similarity index 100% rename from src/api/framework/Core/Paging/IPagedList.cs rename to src/framework/Core/Paging/IPagedList.cs diff --git a/src/api/framework/Core/Paging/PagedList.cs b/src/framework/Core/Paging/PagedList.cs similarity index 100% rename from src/api/framework/Core/Paging/PagedList.cs rename to src/framework/Core/Paging/PagedList.cs diff --git a/src/api/framework/Core/Paging/PaginationFilter.cs b/src/framework/Core/Paging/PaginationFilter.cs similarity index 100% rename from src/api/framework/Core/Paging/PaginationFilter.cs rename to src/framework/Core/Paging/PaginationFilter.cs diff --git a/src/api/framework/Core/Paging/Search.cs b/src/framework/Core/Paging/Search.cs similarity index 100% rename from src/api/framework/Core/Paging/Search.cs rename to src/framework/Core/Paging/Search.cs diff --git a/src/api/framework/Core/Persistence/DatabaseOptions.cs b/src/framework/Core/Persistence/DatabaseOptions.cs similarity index 100% rename from src/api/framework/Core/Persistence/DatabaseOptions.cs rename to src/framework/Core/Persistence/DatabaseOptions.cs diff --git a/src/api/framework/Core/Persistence/IConnectionStringValidator.cs b/src/framework/Core/Persistence/IConnectionStringValidator.cs similarity index 100% rename from src/api/framework/Core/Persistence/IConnectionStringValidator.cs rename to src/framework/Core/Persistence/IConnectionStringValidator.cs diff --git a/src/api/framework/Core/Persistence/IDbInitializer.cs b/src/framework/Core/Persistence/IDbInitializer.cs similarity index 100% rename from src/api/framework/Core/Persistence/IDbInitializer.cs rename to src/framework/Core/Persistence/IDbInitializer.cs diff --git a/src/api/framework/Core/Persistence/IRepository.cs b/src/framework/Core/Persistence/IRepository.cs similarity index 100% rename from src/api/framework/Core/Persistence/IRepository.cs rename to src/framework/Core/Persistence/IRepository.cs diff --git a/src/api/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs b/src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs similarity index 100% rename from src/api/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs rename to src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs diff --git a/src/api/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs b/src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs similarity index 100% rename from src/api/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs rename to src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs diff --git a/src/api/framework/Core/Specifications/SpecificationBuilderExtensions.cs b/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs similarity index 100% rename from src/api/framework/Core/Specifications/SpecificationBuilderExtensions.cs rename to src/framework/Core/Specifications/SpecificationBuilderExtensions.cs diff --git a/src/api/framework/Core/Storage/File/Features/FileUploadCommand.cs b/src/framework/Core/Storage/File/Features/FileUploadCommand.cs similarity index 100% rename from src/api/framework/Core/Storage/File/Features/FileUploadCommand.cs rename to src/framework/Core/Storage/File/Features/FileUploadCommand.cs diff --git a/src/api/framework/Core/Storage/File/Features/FileUploadResponse.cs b/src/framework/Core/Storage/File/Features/FileUploadResponse.cs similarity index 100% rename from src/api/framework/Core/Storage/File/Features/FileUploadResponse.cs rename to src/framework/Core/Storage/File/Features/FileUploadResponse.cs diff --git a/src/api/framework/Core/Storage/File/Features/FileUploadValidator.cs b/src/framework/Core/Storage/File/Features/FileUploadValidator.cs similarity index 100% rename from src/api/framework/Core/Storage/File/Features/FileUploadValidator.cs rename to src/framework/Core/Storage/File/Features/FileUploadValidator.cs diff --git a/src/api/framework/Core/Storage/File/FileType.cs b/src/framework/Core/Storage/File/FileType.cs similarity index 100% rename from src/api/framework/Core/Storage/File/FileType.cs rename to src/framework/Core/Storage/File/FileType.cs diff --git a/src/api/framework/Core/Storage/IStorageService.cs b/src/framework/Core/Storage/IStorageService.cs similarity index 100% rename from src/api/framework/Core/Storage/IStorageService.cs rename to src/framework/Core/Storage/IStorageService.cs diff --git a/src/api/framework/Core/Tenant/Abstractions/ITenantService.cs b/src/framework/Core/Tenant/Abstractions/ITenantService.cs similarity index 100% rename from src/api/framework/Core/Tenant/Abstractions/ITenantService.cs rename to src/framework/Core/Tenant/Abstractions/ITenantService.cs diff --git a/src/api/framework/Core/Tenant/Dtos/TenantDetail.cs b/src/framework/Core/Tenant/Dtos/TenantDetail.cs similarity index 100% rename from src/api/framework/Core/Tenant/Dtos/TenantDetail.cs rename to src/framework/Core/Tenant/Dtos/TenantDetail.cs diff --git a/src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs rename to src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs diff --git a/src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs rename to src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs diff --git a/src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs rename to src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs diff --git a/src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs rename to src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs diff --git a/src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs rename to src/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs diff --git a/src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs rename to src/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs diff --git a/src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs rename to src/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs diff --git a/src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs rename to src/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs diff --git a/src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs rename to src/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs diff --git a/src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs rename to src/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs diff --git a/src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs rename to src/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs diff --git a/src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs rename to src/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs diff --git a/src/api/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs b/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs rename to src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs diff --git a/src/api/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs b/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs rename to src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs diff --git a/src/api/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs b/src/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs rename to src/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs diff --git a/src/api/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs b/src/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs rename to src/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs diff --git a/src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs rename to src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs diff --git a/src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs rename to src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs diff --git a/src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs rename to src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs diff --git a/src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs similarity index 100% rename from src/api/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs rename to src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln new file mode 100644 index 000000000..9d0081f3f --- /dev/null +++ b/src/framework/FSH.Framework.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{60DF219E-E1EB-428E-BB1F-F0342D42699F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing", "Auditing\Auditing.csproj", "{AB2C0DA8-74CA-42AB-BD50-D0162463742A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Release|Any CPU.Build.0 = Release|Any CPU + {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Release|Any CPU.Build.0 = Release|Any CPU + {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/api/framework/Infrastructure/Auth/CurrentUserMiddleware.cs b/src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/CurrentUserMiddleware.cs rename to src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs diff --git a/src/api/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs b/src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs rename to src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs diff --git a/src/api/framework/Infrastructure/Auth/Jwt/Extensions.cs b/src/framework/Infrastructure/Auth/Jwt/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Jwt/Extensions.cs rename to src/framework/Infrastructure/Auth/Jwt/Extensions.cs diff --git a/src/api/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs b/src/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs rename to src/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs diff --git a/src/api/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs b/src/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs rename to src/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs diff --git a/src/api/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs b/src/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs rename to src/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs diff --git a/src/api/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs b/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs rename to src/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs diff --git a/src/api/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs rename to src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs diff --git a/src/api/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs b/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs similarity index 100% rename from src/api/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs rename to src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs diff --git a/src/api/framework/Infrastructure/Behaviours/ValidationBehavior.cs b/src/framework/Infrastructure/Behaviours/ValidationBehavior.cs similarity index 100% rename from src/api/framework/Infrastructure/Behaviours/ValidationBehavior.cs rename to src/framework/Infrastructure/Behaviours/ValidationBehavior.cs diff --git a/src/api/framework/Infrastructure/Caching/DistributedCacheService.cs b/src/framework/Infrastructure/Caching/DistributedCacheService.cs similarity index 100% rename from src/api/framework/Infrastructure/Caching/DistributedCacheService.cs rename to src/framework/Infrastructure/Caching/DistributedCacheService.cs diff --git a/src/api/framework/Infrastructure/Caching/Extensions.cs b/src/framework/Infrastructure/Caching/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Caching/Extensions.cs rename to src/framework/Infrastructure/Caching/Extensions.cs diff --git a/src/api/framework/Infrastructure/Common/Extensions/EnumExtensions.cs b/src/framework/Infrastructure/Common/Extensions/EnumExtensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Common/Extensions/EnumExtensions.cs rename to src/framework/Infrastructure/Common/Extensions/EnumExtensions.cs diff --git a/src/api/framework/Infrastructure/Common/Extensions/RegexExtensions.cs b/src/framework/Infrastructure/Common/Extensions/RegexExtensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Common/Extensions/RegexExtensions.cs rename to src/framework/Infrastructure/Common/Extensions/RegexExtensions.cs diff --git a/src/api/framework/Infrastructure/Constants/QueryStringKeys.cs b/src/framework/Infrastructure/Constants/QueryStringKeys.cs similarity index 100% rename from src/api/framework/Infrastructure/Constants/QueryStringKeys.cs rename to src/framework/Infrastructure/Constants/QueryStringKeys.cs diff --git a/src/api/framework/Infrastructure/Cors/CorsOptions.cs b/src/framework/Infrastructure/Cors/CorsOptions.cs similarity index 100% rename from src/api/framework/Infrastructure/Cors/CorsOptions.cs rename to src/framework/Infrastructure/Cors/CorsOptions.cs diff --git a/src/api/framework/Infrastructure/Cors/Extensions.cs b/src/framework/Infrastructure/Cors/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Cors/Extensions.cs rename to src/framework/Infrastructure/Cors/Extensions.cs diff --git a/src/api/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs b/src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs similarity index 100% rename from src/api/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs rename to src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs diff --git a/src/api/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Extensions.cs rename to src/framework/Infrastructure/Extensions.cs diff --git a/src/api/framework/Infrastructure/FshInfrastructure.cs b/src/framework/Infrastructure/FshInfrastructure.cs similarity index 100% rename from src/api/framework/Infrastructure/FshInfrastructure.cs rename to src/framework/Infrastructure/FshInfrastructure.cs diff --git a/src/api/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs b/src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs rename to src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs diff --git a/src/api/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs b/src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs similarity index 100% rename from src/api/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs rename to src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs diff --git a/src/api/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs b/src/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs rename to src/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Extensions.cs b/src/framework/Infrastructure/Identity/Extensions.cs similarity index 98% rename from src/api/framework/Infrastructure/Identity/Extensions.cs rename to src/framework/Infrastructure/Identity/Extensions.cs index 4d2055929..aa70ce357 100644 --- a/src/api/framework/Infrastructure/Identity/Extensions.cs +++ b/src/framework/Infrastructure/Identity/Extensions.cs @@ -1,4 +1,5 @@ using FSH.Framework.Core.Audit; +using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Core.Identity.Roles; using FSH.Framework.Core.Identity.Tokens; using FSH.Framework.Core.Identity.Users.Abstractions; diff --git a/src/api/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs b/src/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs rename to src/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs diff --git a/src/api/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs b/src/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs rename to src/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs diff --git a/src/api/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs b/src/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs rename to src/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs diff --git a/src/api/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs b/src/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs rename to src/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs rename to src/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs rename to src/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs rename to src/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs rename to src/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs rename to src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs rename to src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs rename to src/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/FshRole.cs b/src/framework/Infrastructure/Identity/Roles/FshRole.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Roles/FshRole.cs rename to src/framework/Infrastructure/Identity/Roles/FshRole.cs diff --git a/src/api/framework/Infrastructure/Identity/Roles/RoleService.cs b/src/framework/Infrastructure/Identity/Roles/RoleService.cs similarity index 98% rename from src/api/framework/Infrastructure/Identity/Roles/RoleService.cs rename to src/framework/Infrastructure/Identity/Roles/RoleService.cs index 6930ab0e1..1b6020853 100644 --- a/src/api/framework/Infrastructure/Identity/Roles/RoleService.cs +++ b/src/framework/Infrastructure/Identity/Roles/RoleService.cs @@ -1,9 +1,9 @@ using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Core.Identity.Roles; using FSH.Framework.Core.Identity.Roles.Features.CreateOrUpdateRole; using FSH.Framework.Core.Identity.Roles.Features.UpdatePermissions; -using FSH.Framework.Core.Identity.Users.Abstractions; using FSH.Framework.Infrastructure.Identity.Persistence; using FSH.Framework.Infrastructure.Identity.RoleClaims; using FSH.Framework.Infrastructure.Tenant; diff --git a/src/api/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs b/src/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs rename to src/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs diff --git a/src/api/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs b/src/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs rename to src/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs b/src/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs rename to src/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Tokens/TokenService.cs b/src/framework/Infrastructure/Identity/Tokens/TokenService.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Tokens/TokenService.cs rename to src/framework/Infrastructure/Identity/Tokens/TokenService.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/ConfirmEmailEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/ConfirmEmailEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/ConfirmEmailEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/ConfirmEmailEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/DeleteUserEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/DeleteUserEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/DeleteUserEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/DeleteUserEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/ForgotPasswordEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/ForgotPasswordEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/ForgotPasswordEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/ForgotPasswordEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/GetUserEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserPermissionsEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserPermissionsEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserPermissionsEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/GetUserPermissionsEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserProfileEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserProfileEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserProfileEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/GetUserProfileEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUsersListEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/GetUsersListEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/GetUsersListEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/GetUsersListEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/RegisterUserEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/RegisterUserEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/RegisterUserEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/RegisterUserEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/ResetPasswordEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/ResetPasswordEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/ResetPasswordEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/ResetPasswordEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/SelfRegisterUserEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/SelfRegisterUserEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/SelfRegisterUserEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/SelfRegisterUserEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/ToggleUserStatusEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/ToggleUserStatusEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/ToggleUserStatusEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/ToggleUserStatusEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Endpoints/UpdateUserEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/UpdateUserEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Endpoints/UpdateUserEndpoint.cs rename to src/framework/Infrastructure/Identity/Users/Endpoints/UpdateUserEndpoint.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/FshUser.cs b/src/framework/Infrastructure/Identity/Users/FshUser.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/FshUser.cs rename to src/framework/Infrastructure/Identity/Users/FshUser.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs b/src/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs similarity index 97% rename from src/api/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs rename to src/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs index 2fcfea6fb..9c67edc36 100644 --- a/src/api/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs +++ b/src/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs @@ -1,5 +1,6 @@ using System.Security.Claims; using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Core.Identity.Users.Abstractions; using FSH.Starter.Shared.Authorization; diff --git a/src/api/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs b/src/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs rename to src/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs b/src/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs rename to src/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs diff --git a/src/api/framework/Infrastructure/Identity/Users/Services/UserService.cs b/src/framework/Infrastructure/Identity/Users/Services/UserService.cs similarity index 100% rename from src/api/framework/Infrastructure/Identity/Users/Services/UserService.cs rename to src/framework/Infrastructure/Identity/Users/Services/UserService.cs diff --git a/src/api/framework/Infrastructure/Infrastructure.csproj b/src/framework/Infrastructure/Infrastructure.csproj similarity index 75% rename from src/api/framework/Infrastructure/Infrastructure.csproj rename to src/framework/Infrastructure/Infrastructure.csproj index 389248b9c..cad185ec2 100644 --- a/src/api/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Infrastructure/Infrastructure.csproj @@ -2,16 +2,7 @@ FSH.Framework.Infrastructure FSH.Framework.Infrastructure - true - - - - - - - - @@ -65,18 +56,7 @@ - - - - - - - - - - - - + diff --git a/src/api/framework/Infrastructure/Jobs/Extensions.cs b/src/framework/Infrastructure/Jobs/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Jobs/Extensions.cs rename to src/framework/Infrastructure/Jobs/Extensions.cs diff --git a/src/api/framework/Infrastructure/Jobs/FshJobActivator.cs b/src/framework/Infrastructure/Jobs/FshJobActivator.cs similarity index 100% rename from src/api/framework/Infrastructure/Jobs/FshJobActivator.cs rename to src/framework/Infrastructure/Jobs/FshJobActivator.cs diff --git a/src/api/framework/Infrastructure/Jobs/FshJobFilter.cs b/src/framework/Infrastructure/Jobs/FshJobFilter.cs similarity index 100% rename from src/api/framework/Infrastructure/Jobs/FshJobFilter.cs rename to src/framework/Infrastructure/Jobs/FshJobFilter.cs diff --git a/src/api/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs b/src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs similarity index 100% rename from src/api/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs rename to src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs diff --git a/src/api/framework/Infrastructure/Jobs/HangfireOptions.cs b/src/framework/Infrastructure/Jobs/HangfireOptions.cs similarity index 100% rename from src/api/framework/Infrastructure/Jobs/HangfireOptions.cs rename to src/framework/Infrastructure/Jobs/HangfireOptions.cs diff --git a/src/api/framework/Infrastructure/Jobs/HangfireService.cs b/src/framework/Infrastructure/Jobs/HangfireService.cs similarity index 100% rename from src/api/framework/Infrastructure/Jobs/HangfireService.cs rename to src/framework/Infrastructure/Jobs/HangfireService.cs diff --git a/src/api/framework/Infrastructure/Jobs/LogJobFilter.cs b/src/framework/Infrastructure/Jobs/LogJobFilter.cs similarity index 100% rename from src/api/framework/Infrastructure/Jobs/LogJobFilter.cs rename to src/framework/Infrastructure/Jobs/LogJobFilter.cs diff --git a/src/api/framework/Infrastructure/Logging/Serilog/Extensions.cs b/src/framework/Infrastructure/Logging/Serilog/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Logging/Serilog/Extensions.cs rename to src/framework/Infrastructure/Logging/Serilog/Extensions.cs diff --git a/src/api/framework/Infrastructure/Logging/Serilog/StaticLogger.cs b/src/framework/Infrastructure/Logging/Serilog/StaticLogger.cs similarity index 100% rename from src/api/framework/Infrastructure/Logging/Serilog/StaticLogger.cs rename to src/framework/Infrastructure/Logging/Serilog/StaticLogger.cs diff --git a/src/api/framework/Infrastructure/Mail/Extensions.cs b/src/framework/Infrastructure/Mail/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Mail/Extensions.cs rename to src/framework/Infrastructure/Mail/Extensions.cs diff --git a/src/api/framework/Infrastructure/Mail/SmtpMailService.cs b/src/framework/Infrastructure/Mail/SmtpMailService.cs similarity index 100% rename from src/api/framework/Infrastructure/Mail/SmtpMailService.cs rename to src/framework/Infrastructure/Mail/SmtpMailService.cs diff --git a/src/api/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs b/src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs similarity index 100% rename from src/api/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs rename to src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs diff --git a/src/api/framework/Infrastructure/OpenApi/Extensions.cs b/src/framework/Infrastructure/OpenApi/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/OpenApi/Extensions.cs rename to src/framework/Infrastructure/OpenApi/Extensions.cs diff --git a/src/api/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs b/src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs similarity index 100% rename from src/api/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs rename to src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs diff --git a/src/api/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs b/src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs similarity index 100% rename from src/api/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs rename to src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs diff --git a/src/api/framework/Infrastructure/Persistence/DbProviders.cs b/src/framework/Infrastructure/Persistence/DbProviders.cs similarity index 100% rename from src/api/framework/Infrastructure/Persistence/DbProviders.cs rename to src/framework/Infrastructure/Persistence/DbProviders.cs diff --git a/src/api/framework/Infrastructure/Persistence/Extensions.cs b/src/framework/Infrastructure/Persistence/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Persistence/Extensions.cs rename to src/framework/Infrastructure/Persistence/Extensions.cs diff --git a/src/api/framework/Infrastructure/Persistence/FshDbContext.cs b/src/framework/Infrastructure/Persistence/FshDbContext.cs similarity index 100% rename from src/api/framework/Infrastructure/Persistence/FshDbContext.cs rename to src/framework/Infrastructure/Persistence/FshDbContext.cs diff --git a/src/api/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs b/src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs similarity index 100% rename from src/api/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs rename to src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs diff --git a/src/api/framework/Infrastructure/RateLimit/Extensions.cs b/src/framework/Infrastructure/RateLimit/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/RateLimit/Extensions.cs rename to src/framework/Infrastructure/RateLimit/Extensions.cs diff --git a/src/api/framework/Infrastructure/RateLimit/RateLimitOptions.cs b/src/framework/Infrastructure/RateLimit/RateLimitOptions.cs similarity index 100% rename from src/api/framework/Infrastructure/RateLimit/RateLimitOptions.cs rename to src/framework/Infrastructure/RateLimit/RateLimitOptions.cs diff --git a/src/api/framework/Infrastructure/SecurityHeaders/Extensions.cs b/src/framework/Infrastructure/SecurityHeaders/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/SecurityHeaders/Extensions.cs rename to src/framework/Infrastructure/SecurityHeaders/Extensions.cs diff --git a/src/api/framework/Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs b/src/framework/Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs similarity index 100% rename from src/api/framework/Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs rename to src/framework/Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs diff --git a/src/api/framework/Infrastructure/SecurityHeaders/SecurityHeaders.cs b/src/framework/Infrastructure/SecurityHeaders/SecurityHeaders.cs similarity index 100% rename from src/api/framework/Infrastructure/SecurityHeaders/SecurityHeaders.cs rename to src/framework/Infrastructure/SecurityHeaders/SecurityHeaders.cs diff --git a/src/api/framework/Infrastructure/Storage/Files/Extension.cs b/src/framework/Infrastructure/Storage/Files/Extension.cs similarity index 100% rename from src/api/framework/Infrastructure/Storage/Files/Extension.cs rename to src/framework/Infrastructure/Storage/Files/Extension.cs diff --git a/src/api/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs b/src/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs similarity index 100% rename from src/api/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs rename to src/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs diff --git a/src/api/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs b/src/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs rename to src/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs diff --git a/src/api/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs b/src/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs rename to src/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs diff --git a/src/api/framework/Infrastructure/Tenant/Endpoints/CreateTenantEndpoint.cs b/src/framework/Infrastructure/Tenant/Endpoints/CreateTenantEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Endpoints/CreateTenantEndpoint.cs rename to src/framework/Infrastructure/Tenant/Endpoints/CreateTenantEndpoint.cs diff --git a/src/api/framework/Infrastructure/Tenant/Endpoints/DisableTenantEndpoint.cs b/src/framework/Infrastructure/Tenant/Endpoints/DisableTenantEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Endpoints/DisableTenantEndpoint.cs rename to src/framework/Infrastructure/Tenant/Endpoints/DisableTenantEndpoint.cs diff --git a/src/api/framework/Infrastructure/Tenant/Endpoints/Extensions.cs b/src/framework/Infrastructure/Tenant/Endpoints/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Endpoints/Extensions.cs rename to src/framework/Infrastructure/Tenant/Endpoints/Extensions.cs diff --git a/src/api/framework/Infrastructure/Tenant/Endpoints/GetTenantByIdEndpoint.cs b/src/framework/Infrastructure/Tenant/Endpoints/GetTenantByIdEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Endpoints/GetTenantByIdEndpoint.cs rename to src/framework/Infrastructure/Tenant/Endpoints/GetTenantByIdEndpoint.cs diff --git a/src/api/framework/Infrastructure/Tenant/Endpoints/GetTenantsEndpoint.cs b/src/framework/Infrastructure/Tenant/Endpoints/GetTenantsEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Endpoints/GetTenantsEndpoint.cs rename to src/framework/Infrastructure/Tenant/Endpoints/GetTenantsEndpoint.cs diff --git a/src/api/framework/Infrastructure/Tenant/Endpoints/UpgradeSubscriptionEndpoint.cs b/src/framework/Infrastructure/Tenant/Endpoints/UpgradeSubscriptionEndpoint.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Endpoints/UpgradeSubscriptionEndpoint.cs rename to src/framework/Infrastructure/Tenant/Endpoints/UpgradeSubscriptionEndpoint.cs diff --git a/src/api/framework/Infrastructure/Tenant/Extensions.cs b/src/framework/Infrastructure/Tenant/Extensions.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Extensions.cs rename to src/framework/Infrastructure/Tenant/Extensions.cs diff --git a/src/api/framework/Infrastructure/Tenant/FshTenantInfo.cs b/src/framework/Infrastructure/Tenant/FshTenantInfo.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/FshTenantInfo.cs rename to src/framework/Infrastructure/Tenant/FshTenantInfo.cs diff --git a/src/api/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs b/src/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs rename to src/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs diff --git a/src/api/framework/Infrastructure/Tenant/Services/TenantService.cs b/src/framework/Infrastructure/Tenant/Services/TenantService.cs similarity index 100% rename from src/api/framework/Infrastructure/Tenant/Services/TenantService.cs rename to src/framework/Infrastructure/Tenant/Services/TenantService.cs diff --git a/src/pos/api/FSH.POS.sln b/src/pos/api/FSH.POS.sln new file mode 100644 index 000000000..58ea56664 --- /dev/null +++ b/src/pos/api/FSH.POS.sln @@ -0,0 +1,14 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal From 70a404edc6e4fa1ab4215c438ef0549283dece18 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 8 Apr 2025 13:28:58 +0530 Subject: [PATCH 02/54] rewrite paging --- src/framework/Application/Application.csproj | 19 +++++++++ .../Behaviors/ValidationBehavior.cs | 23 +++++++++++ .../Application/Exceptions/CustomException.cs | 41 +++++++++++++++++++ .../Exceptions/ForbiddenException.cs | 24 +++++++++++ .../Exceptions/NotFoundException.cs | 19 +++++++++ .../Exceptions/UnauthorizedException.cs | 24 +++++++++++ .../Extensions/PagedListExtensions.cs | 12 ++++++ .../Extensions/RepositoryExtensions.cs} | 16 +++++--- .../Extensions/ServiceCollectionExtensions.cs | 10 +++++ src/framework/Core/Core.csproj | 1 - .../Core/Exceptions/CustomException.cs | 17 -------- .../Core/Exceptions/ForbiddenException.cs | 14 ------- src/framework/Core/Exceptions/FshException.cs | 21 ---------- .../Core/Exceptions/NotFoundException.cs | 11 ----- .../Core/Exceptions/UnauthorizedException.cs | 15 ------- src/framework/Core/Paging/Filter.cs | 27 +++--------- src/framework/Core/Paging/FilterLogic.cs | 8 ++++ src/framework/Core/Paging/FilterOperator.cs | 14 +++++++ src/framework/Core/Paging/IPageRequest.cs | 10 +++++ src/framework/Core/Paging/IPagedList.cs | 16 +++----- src/framework/Core/Paging/PagedList.cs | 31 +++++++------- src/framework/Core/Paging/PaginationFilter.cs | 16 +++----- .../Core/Paging/PaginationFilterExtensions.cs | 10 +++++ src/framework/Core/Paging/Search.cs | 18 +++++++- src/framework/FSH.Framework.sln | 6 +++ 25 files changed, 279 insertions(+), 144 deletions(-) create mode 100644 src/framework/Application/Application.csproj create mode 100644 src/framework/Application/Behaviors/ValidationBehavior.cs create mode 100644 src/framework/Application/Exceptions/CustomException.cs create mode 100644 src/framework/Application/Exceptions/ForbiddenException.cs create mode 100644 src/framework/Application/Exceptions/NotFoundException.cs create mode 100644 src/framework/Application/Exceptions/UnauthorizedException.cs create mode 100644 src/framework/Application/Extensions/PagedListExtensions.cs rename src/framework/{Core/Paging/Extensions.cs => Application/Extensions/RepositoryExtensions.cs} (50%) create mode 100644 src/framework/Application/Extensions/ServiceCollectionExtensions.cs delete mode 100644 src/framework/Core/Exceptions/CustomException.cs delete mode 100644 src/framework/Core/Exceptions/ForbiddenException.cs delete mode 100644 src/framework/Core/Exceptions/FshException.cs delete mode 100644 src/framework/Core/Exceptions/NotFoundException.cs delete mode 100644 src/framework/Core/Exceptions/UnauthorizedException.cs create mode 100644 src/framework/Core/Paging/FilterLogic.cs create mode 100644 src/framework/Core/Paging/FilterOperator.cs create mode 100644 src/framework/Core/Paging/PaginationFilterExtensions.cs diff --git a/src/framework/Application/Application.csproj b/src/framework/Application/Application.csproj new file mode 100644 index 000000000..2924ab08d --- /dev/null +++ b/src/framework/Application/Application.csproj @@ -0,0 +1,19 @@ + + + FSH.Framework.Application + FSH.Framework.Application + + + net9.0 + enable + enable + + + + + + + + + + diff --git a/src/framework/Application/Behaviors/ValidationBehavior.cs b/src/framework/Application/Behaviors/ValidationBehavior.cs new file mode 100644 index 000000000..f3ae4fa8f --- /dev/null +++ b/src/framework/Application/Behaviors/ValidationBehavior.cs @@ -0,0 +1,23 @@ +using FluentValidation; +using MediatR; + +namespace FSH.Framework.Application.Behaviours; +public class ValidationBehavior(IEnumerable> validators) : IPipelineBehavior + where TRequest : IRequest +{ + private readonly IEnumerable> _validators = validators; + + public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + { + if (_validators.Any()) + { + var context = new ValidationContext(request); + var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken))); + var failures = validationResults.SelectMany(r => r.Errors).Where(f => f != null).ToList(); + + if (failures.Count > 0) + throw new ValidationException(failures); + } + return await next(); + } +} diff --git a/src/framework/Application/Exceptions/CustomException.cs b/src/framework/Application/Exceptions/CustomException.cs new file mode 100644 index 000000000..4143639ff --- /dev/null +++ b/src/framework/Application/Exceptions/CustomException.cs @@ -0,0 +1,41 @@ +using System.Net; + +namespace FSH.Framework.Application.Exceptions; + +/// +/// FullStackHero exception used for consistent error handling across the stack. +/// Includes HTTP status codes and optional detailed error messages. +/// +public class CustomException : Exception +{ + /// + /// A list of error messages (e.g., validation errors, business rules). + /// + public IReadOnlyList ErrorMessages { get; } + + /// + /// The HTTP status code associated with this exception. + /// + public HttpStatusCode StatusCode { get; } + + public CustomException( + string message, + IEnumerable? errors = null, + HttpStatusCode statusCode = HttpStatusCode.InternalServerError) + : base(message) + { + ErrorMessages = errors?.ToList() ?? new List(); + StatusCode = statusCode; + } + + public CustomException( + string message, + Exception innerException, + IEnumerable? errors = null, + HttpStatusCode statusCode = HttpStatusCode.InternalServerError) + : base(message, innerException) + { + ErrorMessages = errors?.ToList() ?? new List(); + StatusCode = statusCode; + } +} diff --git a/src/framework/Application/Exceptions/ForbiddenException.cs b/src/framework/Application/Exceptions/ForbiddenException.cs new file mode 100644 index 000000000..d35d4b187 --- /dev/null +++ b/src/framework/Application/Exceptions/ForbiddenException.cs @@ -0,0 +1,24 @@ +using System.Net; + +namespace FSH.Framework.Application.Exceptions; + +/// +/// Exception representing a 403 Forbidden error. +/// +public class ForbiddenException : CustomException +{ + public ForbiddenException() + : base("Unauthorized access.", Array.Empty(), HttpStatusCode.Forbidden) + { + } + + public ForbiddenException(string message) + : base(message, Array.Empty(), HttpStatusCode.Forbidden) + { + } + + public ForbiddenException(string message, IEnumerable errors) + : base(message, errors.ToList(), HttpStatusCode.Forbidden) + { + } +} diff --git a/src/framework/Application/Exceptions/NotFoundException.cs b/src/framework/Application/Exceptions/NotFoundException.cs new file mode 100644 index 000000000..5edcad79c --- /dev/null +++ b/src/framework/Application/Exceptions/NotFoundException.cs @@ -0,0 +1,19 @@ +using System.Net; + +namespace FSH.Framework.Application.Exceptions; + +/// +/// Exception representing a 404 Not Found error. +/// +public class NotFoundException : CustomException +{ + public NotFoundException(string message) + : base(message, Array.Empty(), HttpStatusCode.NotFound) + { + } + + public NotFoundException(string message, IEnumerable errors) + : base(message, errors.ToList(), HttpStatusCode.NotFound) + { + } +} diff --git a/src/framework/Application/Exceptions/UnauthorizedException.cs b/src/framework/Application/Exceptions/UnauthorizedException.cs new file mode 100644 index 000000000..50264ed12 --- /dev/null +++ b/src/framework/Application/Exceptions/UnauthorizedException.cs @@ -0,0 +1,24 @@ +using System.Net; + +namespace FSH.Framework.Application.Exceptions; + +/// +/// Exception representing a 401 Unauthorized error (authentication failure). +/// +public class UnauthorizedException : CustomException +{ + public UnauthorizedException() + : base("Authentication failed.", Array.Empty(), HttpStatusCode.Unauthorized) + { + } + + public UnauthorizedException(string message) + : base(message, Array.Empty(), HttpStatusCode.Unauthorized) + { + } + + public UnauthorizedException(string message, IEnumerable errors) + : base(message, errors.ToList(), HttpStatusCode.Unauthorized) + { + } +} diff --git a/src/framework/Application/Extensions/PagedListExtensions.cs b/src/framework/Application/Extensions/PagedListExtensions.cs new file mode 100644 index 000000000..bad0b79d1 --- /dev/null +++ b/src/framework/Application/Extensions/PagedListExtensions.cs @@ -0,0 +1,12 @@ +using FSH.Framework.Core.Paging; +using Mapster; + +namespace FSH.Framework.Application.Extensions; + +public static class PagedListExtensions +{ + public static PagedList AdaptPagedList(this PagedList paged) + where T : class + where TR : class => + new(paged.Items.Adapt>(), paged.PageNumber, paged.PageSize, paged.TotalCount); +} diff --git a/src/framework/Core/Paging/Extensions.cs b/src/framework/Application/Extensions/RepositoryExtensions.cs similarity index 50% rename from src/framework/Core/Paging/Extensions.cs rename to src/framework/Application/Extensions/RepositoryExtensions.cs index a9c5544eb..3596667a5 100644 --- a/src/framework/Core/Paging/Extensions.cs +++ b/src/framework/Application/Extensions/RepositoryExtensions.cs @@ -1,17 +1,21 @@ using Ardalis.Specification; +using FSH.Framework.Core.Paging; -namespace FSH.Framework.Core.Paging; -public static class Extensions +namespace FSH.Framework.Application.Extensions; +public static class RepositoryExtensions { public static async Task> PaginatedListAsync( - this IReadRepositoryBase repository, ISpecification spec, PaginationFilter filter, CancellationToken cancellationToken = default) - where T : class - where TDestination : class + this IReadRepositoryBase repository, + ISpecification spec, + PaginationFilter filter, + CancellationToken cancellationToken = default) + where T : class + where TDestination : class { ArgumentNullException.ThrowIfNull(repository); var items = await repository.ListAsync(spec, cancellationToken).ConfigureAwait(false); - int totalCount = await repository.CountAsync(spec, cancellationToken).ConfigureAwait(false); + var totalCount = await repository.CountAsync(spec, cancellationToken).ConfigureAwait(false); return new PagedList(items, filter.PageNumber, filter.PageSize, totalCount); } diff --git a/src/framework/Application/Extensions/ServiceCollectionExtensions.cs b/src/framework/Application/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..1aff1b794 --- /dev/null +++ b/src/framework/Application/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FSH.Framework.Application.Extensions; +internal class ServiceCollectionExtensions +{ +} diff --git a/src/framework/Core/Core.csproj b/src/framework/Core/Core.csproj index aa4ae8c10..0cbd9722c 100644 --- a/src/framework/Core/Core.csproj +++ b/src/framework/Core/Core.csproj @@ -7,7 +7,6 @@ - diff --git a/src/framework/Core/Exceptions/CustomException.cs b/src/framework/Core/Exceptions/CustomException.cs deleted file mode 100644 index 4d1af9af9..000000000 --- a/src/framework/Core/Exceptions/CustomException.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Net; - -namespace FSH.Framework.Core.Exceptions; - -public class CustomException : Exception -{ - public List? ErrorMessages { get; } - - public HttpStatusCode StatusCode { get; } - - public CustomException(string message, List? errors = default, HttpStatusCode statusCode = HttpStatusCode.InternalServerError) - : base(message) - { - ErrorMessages = errors; - StatusCode = statusCode; - } -} diff --git a/src/framework/Core/Exceptions/ForbiddenException.cs b/src/framework/Core/Exceptions/ForbiddenException.cs deleted file mode 100644 index fdafead90..000000000 --- a/src/framework/Core/Exceptions/ForbiddenException.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Net; - -namespace FSH.Framework.Core.Exceptions; -public class ForbiddenException : FshException -{ - public ForbiddenException() - : base("unauthorized", [], HttpStatusCode.Forbidden) - { - } - public ForbiddenException(string message) - : base(message, [], HttpStatusCode.Forbidden) - { - } -} diff --git a/src/framework/Core/Exceptions/FshException.cs b/src/framework/Core/Exceptions/FshException.cs deleted file mode 100644 index 28597c529..000000000 --- a/src/framework/Core/Exceptions/FshException.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Net; - -namespace FSH.Framework.Core.Exceptions; -public class FshException : Exception -{ - public IEnumerable ErrorMessages { get; } - - public HttpStatusCode StatusCode { get; } - - public FshException(string message, IEnumerable errors, HttpStatusCode statusCode = HttpStatusCode.InternalServerError) - : base(message) - { - ErrorMessages = errors; - StatusCode = statusCode; - } - - public FshException(string message) : base(message) - { - ErrorMessages = new List(); - } -} diff --git a/src/framework/Core/Exceptions/NotFoundException.cs b/src/framework/Core/Exceptions/NotFoundException.cs deleted file mode 100644 index 351e25cfc..000000000 --- a/src/framework/Core/Exceptions/NotFoundException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.ObjectModel; -using System.Net; - -namespace FSH.Framework.Core.Exceptions; -public class NotFoundException : FshException -{ - public NotFoundException(string message) - : base(message, new Collection(), HttpStatusCode.NotFound) - { - } -} diff --git a/src/framework/Core/Exceptions/UnauthorizedException.cs b/src/framework/Core/Exceptions/UnauthorizedException.cs deleted file mode 100644 index 559eb060c..000000000 --- a/src/framework/Core/Exceptions/UnauthorizedException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.ObjectModel; -using System.Net; - -namespace FSH.Framework.Core.Exceptions; -public class UnauthorizedException : FshException -{ - public UnauthorizedException() - : base("authentication failed", new Collection(), HttpStatusCode.Unauthorized) - { - } - public UnauthorizedException(string message) - : base(message, new Collection(), HttpStatusCode.Unauthorized) - { - } -} diff --git a/src/framework/Core/Paging/Filter.cs b/src/framework/Core/Paging/Filter.cs index fdbdc2938..6407996e6 100644 --- a/src/framework/Core/Paging/Filter.cs +++ b/src/framework/Core/Paging/Filter.cs @@ -1,34 +1,17 @@ namespace FSH.Framework.Core.Paging; -public static class FilterOperator -{ - public const string EQ = "eq"; - public const string NEQ = "neq"; - public const string LT = "lt"; - public const string LTE = "lte"; - public const string GT = "gt"; - public const string GTE = "gte"; - public const string STARTSWITH = "startswith"; - public const string ENDSWITH = "endswith"; - public const string CONTAINS = "contains"; -} - -public static class FilterLogic -{ - public const string AND = "and"; - public const string OR = "or"; - public const string XOR = "xor"; -} - +/// +/// Represents a filter expression used for dynamic querying. +/// public class Filter { - public string? Logic { get; set; } + public FilterLogic? Logic { get; set; } public IEnumerable? Filters { get; set; } public string? Field { get; set; } - public string? Operator { get; set; } + public FilterOperator? Operator { get; set; } public object? Value { get; set; } } diff --git a/src/framework/Core/Paging/FilterLogic.cs b/src/framework/Core/Paging/FilterLogic.cs new file mode 100644 index 000000000..51767a14b --- /dev/null +++ b/src/framework/Core/Paging/FilterLogic.cs @@ -0,0 +1,8 @@ +namespace FSH.Framework.Core.Paging; + +public enum FilterLogic +{ + And, + Or, + Xor +} diff --git a/src/framework/Core/Paging/FilterOperator.cs b/src/framework/Core/Paging/FilterOperator.cs new file mode 100644 index 000000000..0887f7e1f --- /dev/null +++ b/src/framework/Core/Paging/FilterOperator.cs @@ -0,0 +1,14 @@ +namespace FSH.Framework.Core.Paging; + +public enum FilterOperator +{ + Eq, + Neq, + Lt, + Lte, + Gt, + Gte, + StartsWith, + EndsWith, + Contains +} diff --git a/src/framework/Core/Paging/IPageRequest.cs b/src/framework/Core/Paging/IPageRequest.cs index c4a2a7f14..6d712599c 100644 --- a/src/framework/Core/Paging/IPageRequest.cs +++ b/src/framework/Core/Paging/IPageRequest.cs @@ -1,9 +1,19 @@ namespace FSH.Framework.Core.Paging; +/// +/// Represents a paginated query request with optional filtering and sorting. +/// public interface IPageRequest { + /// Page number (1-based). int PageNumber { get; init; } + + /// Number of items per page. int PageSize { get; init; } + + /// Optional filter expression (raw or JSON). string? Filters { get; init; } + + /// Optional sort order (e.g., "name asc", "created desc"). string? SortOrder { get; init; } } diff --git a/src/framework/Core/Paging/IPagedList.cs b/src/framework/Core/Paging/IPagedList.cs index e2950b398..c55b50726 100644 --- a/src/framework/Core/Paging/IPagedList.cs +++ b/src/framework/Core/Paging/IPagedList.cs @@ -1,18 +1,12 @@ namespace FSH.Framework.Core.Paging; -public interface IPagedList - where T : class +public interface IPagedList { + IReadOnlyList Items { get; } + int PageNumber { get; } + int PageSize { get; } + int TotalCount { get; } int TotalPages { get; } bool HasPrevious { get; } bool HasNext { get; } - IReadOnlyList Items { get; init; } - int TotalCount { get; init; } - int PageNumber { get; init; } - int PageSize { get; init; } - - IPagedList MapTo(Func map) - where TR : class; - IPagedList MapTo() - where TR : class; } diff --git a/src/framework/Core/Paging/PagedList.cs b/src/framework/Core/Paging/PagedList.cs index 7f48292f7..083664489 100644 --- a/src/framework/Core/Paging/PagedList.cs +++ b/src/framework/Core/Paging/PagedList.cs @@ -1,21 +1,22 @@ -using Mapster; +namespace FSH.Framework.Core.Paging; -namespace FSH.Framework.Core.Paging; - -public record PagedList(IReadOnlyList Items, int PageNumber, int PageSize, int TotalCount) : IPagedList - where T : class +public record PagedList( + IReadOnlyList Items, + int PageNumber, + int PageSize, + int TotalCount +) : IPagedList where T : class { public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize); + public bool HasPrevious => PageNumber > 1; + public bool HasNext => PageNumber < TotalPages; - public IPagedList MapTo(Func map) - where TR : class - { - return new PagedList(Items.Select(map).ToList(), PageNumber, PageSize, TotalCount); - } - public IPagedList MapTo() - where TR : class - { - return new PagedList(Items.Adapt>(), PageNumber, PageSize, TotalCount); - } + + /// + /// Maps the paged list to another paged list using a custom projection. + /// + public PagedList MapTo(Func mapper) + where TR : class => + new(Items.Select(mapper).ToList(), PageNumber, PageSize, TotalCount); } diff --git a/src/framework/Core/Paging/PaginationFilter.cs b/src/framework/Core/Paging/PaginationFilter.cs index 13be4026e..c3920145f 100644 --- a/src/framework/Core/Paging/PaginationFilter.cs +++ b/src/framework/Core/Paging/PaginationFilter.cs @@ -1,15 +1,11 @@ namespace FSH.Framework.Core.Paging; -public class PaginationFilter : BaseFilter +public class PaginationFilter : BaseFilter, IPageRequest { - public int PageNumber { get; set; } + public int PageNumber { get; init; } = 1; + public int PageSize { get; init; } = 10; + public IReadOnlyList? OrderBy { get; init; } - public int PageSize { get; set; } = int.MaxValue; - public string[]? OrderBy { get; set; } -} - -public static class PaginationFilterExtensions -{ - public static bool HasOrderBy(this PaginationFilter filter) => - filter.OrderBy?.Any() is true; + public string? Filters { get; init; } + public string? SortOrder { get; init; } } diff --git a/src/framework/Core/Paging/PaginationFilterExtensions.cs b/src/framework/Core/Paging/PaginationFilterExtensions.cs new file mode 100644 index 000000000..41891100d --- /dev/null +++ b/src/framework/Core/Paging/PaginationFilterExtensions.cs @@ -0,0 +1,10 @@ +namespace FSH.Framework.Core.Paging; + +public static class PaginationFilterExtensions +{ + /// + /// Returns true if the PaginationFilter contains any OrderBy fields. + /// + public static bool HasOrderBy(this PaginationFilter? filter) => + filter?.OrderBy?.Any() == true; +} diff --git a/src/framework/Core/Paging/Search.cs b/src/framework/Core/Paging/Search.cs index a2f262498..ec78cb343 100644 --- a/src/framework/Core/Paging/Search.cs +++ b/src/framework/Core/Paging/Search.cs @@ -1,7 +1,23 @@ namespace FSH.Framework.Core.Paging; +/// +/// Represents a search filter with target fields and a keyword. +/// public class Search { - public List Fields { get; set; } = new(); + /// + /// The list of field names to apply the search keyword against. + /// + public IReadOnlyList Fields { get; set; } = new List(); + + /// + /// The keyword to search for across the specified fields. + /// public string? Keyword { get; set; } + + /// + /// Returns true if both fields and keyword are provided. + /// + public bool IsValid => + Fields?.Count > 0 && !string.IsNullOrWhiteSpace(Keyword); } diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 9d0081f3f..5bec34c1e 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastru EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing", "Auditing\Auditing.csproj", "{AB2C0DA8-74CA-42AB-BD50-D0162463742A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application", "Application\Application.csproj", "{63773336-64B9-4A55-B1EA-EEF18BDF73D9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Debug|Any CPU.Build.0 = Debug|Any CPU {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Release|Any CPU.Build.0 = Release|Any CPU + {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 1f89003c88710af153c773c794e94e1ab4cc3056 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 8 Apr 2025 15:42:32 +0530 Subject: [PATCH 03/54] fix auditing --- src/Directory.Packages.props | 2 +- src/framework/Application/Application.csproj | 3 + .../Abstractions/IAuditService.cs | 4 +- .../Abstractions/IAuditTrailDbContext.cs | 4 +- .../Auditing.Core.csproj} | 13 +- .../Auditing/Auditing.Core/Dtos/AuditTrail.cs | 54 +++++++ .../Auditing.Core/Enums/AuditOperation.cs | 8 ++ .../Events/AuditPublishedEvent.cs | 14 ++ .../Auditing.Endpoints.csproj | 19 +++ .../GetUserAuditTrailEndpoint.cs | 6 +- .../Auditing.Infrastructure.csproj | 16 +++ .../Handlers}/AuditPublishedEventHandler.cs | 5 +- .../Interceptors/AuditInterceptor.cs | 53 +++---- .../Services/AuditService.cs | 6 +- src/framework/Auditing/Dtos/TrailDto.cs | 16 --- src/framework/Auditing/Enums/TrailType.cs | 8 -- .../Auditing/Events/AuditPublishedEvent.cs | 13 -- .../Auditing/Mappings/TrailMapping.cs | 29 ---- src/framework/Auditing/Models/AuditTrail.cs | 13 -- .../UpdatePermissionsCommand.cs | 6 - .../Generate/TokenGenerationCommand.cs | 17 --- .../AssignUserRole/AssignUserRoleCommand.cs | 7 - .../ChangePassword/ChangePasswordCommand.cs | 7 - .../ChangePassword/ChangePasswordValidator.cs | 18 --- .../RegisterUser/RegisterUserResponse.cs | 2 - .../File/Features/FileUploadCommand.cs | 11 -- .../File/Features/FileUploadResponse.cs | 7 - .../File/Features/FileUploadValidator.cs | 21 --- src/framework/Core/Storage/File/FileType.cs | 9 -- src/framework/Core/Storage/FileType.cs | 24 ++++ .../Core/Storage/FileUploadRequest.cs | 7 + .../Storage/FileUploadRequestValidator.cs | 21 +++ src/framework/Core/Storage/IStorageService.cs | 14 +- src/framework/FSH.Framework.sln | 62 +++++++- .../Abstractions/ICurrentUserInitializer.cs | 2 +- .../Abstractions/IUserService.cs | 1 + .../Identity.Core}/Dtos/UserDetail.cs | 2 +- .../Identity.Core}/Dtos/UserRoleDetail.cs | 0 .../Identity.Core/Identity.Core.csproj | 12 ++ .../Identity.Core}/Roles/IRoleService.cs | 5 +- .../Identity.Core}/Roles/RoleDto.cs | 2 +- .../Identity.Core}/Tokens/ITokenService.cs | 2 +- .../Identity.Endpoints.csproj | 19 +++ .../CreateOrUpdateRoleCommand.cs | 2 +- .../CreateOrUpdateRoleValidator.cs | 2 +- .../UpdatePermissionsCommand.cs | 14 ++ .../UpdatePermissionsValidator.cs | 2 +- .../Tokens/Generate/TokenGenerationCommand.cs | 14 ++ .../v1/Tokens}/Refresh/RefreshTokenCommand.cs | 2 +- .../AssignUserRole/AssignUserRoleCommand.cs | 11 ++ .../ChangePassword/ChangePasswordCommand.cs | 13 ++ .../ChangePassword/ChangePasswordValidator.cs | 23 +++ .../ForgotPassword/ForgotPasswordCommand.cs | 2 +- .../ForgotPassword/ForgotPasswordValidator.cs | 2 +- .../RegisterUser/RegisterUserCommand.cs | 2 +- .../RegisterUser/RegisterUserResponse.cs | 2 + .../ResetPassword/ResetPasswordCommand.cs | 2 +- .../ResetPassword/ResetPasswordValidator.cs | 2 +- .../ToggleUserStatusCommand.cs | 2 +- .../v1/Users}/UpdateUser/UpdateUserCommand.cs | 9 +- .../UpdateUser/UpdateUserCommandValidator.cs | 40 ++++++ .../RequiredPermissionAuthorizationHandler.cs | 5 +- .../Identity.Infrastructure.csproj | 15 ++ .../Infrastructure/Infrastructure.csproj | 3 + .../Infrastructure/Storage/Files/Extension.cs | 25 ---- .../Storage/Files/LocalFileStorageService.cs | 133 ------------------ .../Storage/LocalStorageService.cs | 58 ++++++++ .../Storage/StorageServiceRegistration.cs | 14 ++ .../Authorization/EndpointExtensions.cs | 12 ++ .../RequiredPermissionAttribute.cs | 14 ++ src/framework/Shared/Shared.csproj | 14 ++ 71 files changed, 566 insertions(+), 437 deletions(-) rename src/framework/Auditing/{ => Auditing.Core}/Abstractions/IAuditService.cs (50%) rename src/framework/Auditing/{ => Auditing.Core}/Abstractions/IAuditTrailDbContext.cs (66%) rename src/framework/Auditing/{Auditing.csproj => Auditing.Core/Auditing.Core.csproj} (52%) create mode 100644 src/framework/Auditing/Auditing.Core/Dtos/AuditTrail.cs create mode 100644 src/framework/Auditing/Auditing.Core/Enums/AuditOperation.cs create mode 100644 src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj rename src/framework/{Infrastructure/Identity/Audit/Endpoints => Auditing/Auditing.Endpoints/v1/GetUserAudits}/GetUserAuditTrailEndpoint.cs (81%) create mode 100644 src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj rename src/framework/Auditing/{Events => Auditing.Infrastructure/Handlers}/AuditPublishedEventHandler.cs (88%) rename src/framework/Auditing/{ => Auditing.Infrastructure}/Interceptors/AuditInterceptor.cs (75%) rename src/framework/Auditing/{ => Auditing.Infrastructure}/Services/AuditService.cs (73%) delete mode 100644 src/framework/Auditing/Dtos/TrailDto.cs delete mode 100644 src/framework/Auditing/Enums/TrailType.cs delete mode 100644 src/framework/Auditing/Events/AuditPublishedEvent.cs delete mode 100644 src/framework/Auditing/Mappings/TrailMapping.cs delete mode 100644 src/framework/Auditing/Models/AuditTrail.cs delete mode 100644 src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs delete mode 100644 src/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs delete mode 100644 src/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs delete mode 100644 src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs delete mode 100644 src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs delete mode 100644 src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs delete mode 100644 src/framework/Core/Storage/File/Features/FileUploadCommand.cs delete mode 100644 src/framework/Core/Storage/File/Features/FileUploadResponse.cs delete mode 100644 src/framework/Core/Storage/File/Features/FileUploadValidator.cs delete mode 100644 src/framework/Core/Storage/File/FileType.cs create mode 100644 src/framework/Core/Storage/FileType.cs create mode 100644 src/framework/Core/Storage/FileUploadRequest.cs create mode 100644 src/framework/Core/Storage/FileUploadRequestValidator.cs rename src/framework/{Core/Identity/Users => Identity/Identity.Core}/Abstractions/ICurrentUserInitializer.cs (74%) rename src/framework/{Core/Identity/Users => Identity/Identity.Core}/Abstractions/IUserService.cs (98%) rename src/framework/{Core/Identity/Users => Identity/Identity.Core}/Dtos/UserDetail.cs (88%) rename src/framework/{Core/Identity/Users => Identity/Identity.Core}/Dtos/UserRoleDetail.cs (100%) create mode 100644 src/framework/Identity/Identity.Core/Identity.Core.csproj rename src/framework/{Core/Identity => Identity/Identity.Core}/Roles/IRoleService.cs (68%) rename src/framework/{Core/Identity => Identity/Identity.Core}/Roles/RoleDto.cs (81%) rename src/framework/{Core/Identity => Identity/Identity.Core}/Tokens/ITokenService.cs (91%) create mode 100644 src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj rename src/framework/{Core/Identity/Roles/Features => Identity/Identity.Endpoints/v1/Roles}/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs (70%) rename src/framework/{Core/Identity/Roles/Features => Identity/Identity.Endpoints/v1/Roles}/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs (77%) create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs rename src/framework/{Core/Identity/Roles/Features => Identity/Identity.Endpoints/v1/Roles}/UpdatePermissions/UpdatePermissionsValidator.cs (79%) create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs rename src/framework/{Core/Identity/Tokens/Features => Identity/Identity.Endpoints/v1/Tokens}/Refresh/RefreshTokenCommand.cs (85%) create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs rename src/framework/{Core/Identity/Users/Features => Identity/Identity.Endpoints/v1/Users}/ForgotPassword/ForgotPasswordCommand.cs (55%) rename src/framework/{Core/Identity/Users/Features => Identity/Identity.Endpoints/v1/Users}/ForgotPassword/ForgotPasswordValidator.cs (79%) rename src/framework/{Core/Identity/Users/Features => Identity/Identity.Endpoints/v1/Users}/RegisterUser/RegisterUserCommand.cs (89%) create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs rename src/framework/{Core/Identity/Users/Features => Identity/Identity.Endpoints/v1/Users}/ResetPassword/ResetPasswordCommand.cs (73%) rename src/framework/{Core/Identity/Users/Features => Identity/Identity.Endpoints/v1/Users}/ResetPassword/ResetPasswordValidator.cs (81%) rename src/framework/{Core/Identity/Users/Features => Identity/Identity.Endpoints/v1/Users}/ToggleUserStatus/ToggleUserStatusCommand.cs (62%) rename src/framework/{Core/Identity/Users/Features => Identity/Identity.Endpoints/v1/Users}/UpdateUser/UpdateUserCommand.cs (54%) create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs rename src/framework/{Infrastructure/Auth/Policy => Identity/Identity.Infrastructure/Authorization}/RequiredPermissionAuthorizationHandler.cs (86%) create mode 100644 src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj delete mode 100644 src/framework/Infrastructure/Storage/Files/Extension.cs delete mode 100644 src/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs create mode 100644 src/framework/Infrastructure/Storage/LocalStorageService.cs create mode 100644 src/framework/Infrastructure/Storage/StorageServiceRegistration.cs create mode 100644 src/framework/Shared/Authorization/EndpointExtensions.cs create mode 100644 src/framework/Shared/Authorization/RequiredPermissionAttribute.cs create mode 100644 src/framework/Shared/Shared.csproj diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 35dedb554..c1d0d5b2c 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -58,7 +58,7 @@ - + diff --git a/src/framework/Application/Application.csproj b/src/framework/Application/Application.csproj index 2924ab08d..71327fe02 100644 --- a/src/framework/Application/Application.csproj +++ b/src/framework/Application/Application.csproj @@ -16,4 +16,7 @@ + + + diff --git a/src/framework/Auditing/Abstractions/IAuditService.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs similarity index 50% rename from src/framework/Auditing/Abstractions/IAuditService.cs rename to src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs index f7fe84f49..07857b7eb 100644 --- a/src/framework/Auditing/Abstractions/IAuditService.cs +++ b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Auditing.Models; +using FSH.Framework.Auditing.Core.Dtos; -namespace FSH.Framework.Auditing.Abstractions; +namespace FSH.Framework.Auditing.Core.Abstractions; public interface IAuditService { Task> GetUserTrailsAsync(Guid userId); diff --git a/src/framework/Auditing/Abstractions/IAuditTrailDbContext.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditTrailDbContext.cs similarity index 66% rename from src/framework/Auditing/Abstractions/IAuditTrailDbContext.cs rename to src/framework/Auditing/Auditing.Core/Abstractions/IAuditTrailDbContext.cs index 5532bbc89..e43213ab4 100644 --- a/src/framework/Auditing/Abstractions/IAuditTrailDbContext.cs +++ b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditTrailDbContext.cs @@ -1,7 +1,7 @@ -using FSH.Framework.Auditing.Models; +using FSH.Framework.Auditing.Core.Dtos; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Auditing.Abstractions; +namespace FSH.Framework.Auditing.Core.Abstractions; public interface IAuditTrailDbContext { DbSet AuditTrails { get; } diff --git a/src/framework/Auditing/Auditing.csproj b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj similarity index 52% rename from src/framework/Auditing/Auditing.csproj rename to src/framework/Auditing/Auditing.Core/Auditing.Core.csproj index cec8661b6..8bb8eb1ed 100644 --- a/src/framework/Auditing/Auditing.csproj +++ b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj @@ -1,23 +1,16 @@  - FSH.Framework.Auditing - FSH.Framework.Auditing + FSH.Framework.Auditing.Core + FSH.Framework.Auditing.Core net9.0 enable enable - - - - - - - - + diff --git a/src/framework/Auditing/Auditing.Core/Dtos/AuditTrail.cs b/src/framework/Auditing/Auditing.Core/Dtos/AuditTrail.cs new file mode 100644 index 000000000..73ba62c3a --- /dev/null +++ b/src/framework/Auditing/Auditing.Core/Dtos/AuditTrail.cs @@ -0,0 +1,54 @@ +using System.Collections.ObjectModel; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json; +using FSH.Framework.Auditing.Core.Enums; + +namespace FSH.Framework.Auditing.Core.Dtos; + +public class AuditTrail +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } + public DateTimeOffset DateTime { get; set; } + public AuditOperation Operation { get; set; } // e.g., "Create", "Update", "Delete" + public string? EntityName { get; set; } // Name of the entity/table affected + + // Store dictionaries as JSON in the database + [Column(TypeName = "jsonb")] + public string KeyValuesJson { get; set; } = string.Empty; + + [Column(TypeName = "jsonb")] + public string OldValuesJson { get; set; } = string.Empty; + + [Column(TypeName = "jsonb")] + public string NewValuesJson { get; set; } = string.Empty; + + // Store ModifiedProperties as JSON + [Column(TypeName = "jsonb")] + public string ModifiedPropertiesJson { get; set; } = string.Empty; + + // Convert JSON back to Dictionary or List when needed + public Dictionary KeyValues + { + get => JsonSerializer.Deserialize>(KeyValuesJson) ?? new Dictionary(); + set => KeyValuesJson = JsonSerializer.Serialize(value); + } + + public Dictionary OldValues + { + get => JsonSerializer.Deserialize>(OldValuesJson) ?? new Dictionary(); + set => OldValuesJson = JsonSerializer.Serialize(value); + } + + public Dictionary NewValues + { + get => JsonSerializer.Deserialize>(NewValuesJson) ?? new Dictionary(); + set => NewValuesJson = JsonSerializer.Serialize(value); + } + + public Collection ModifiedProperties + { + get => JsonSerializer.Deserialize>(ModifiedPropertiesJson) ?? new Collection(); + set => ModifiedPropertiesJson = JsonSerializer.Serialize(value); + } +} diff --git a/src/framework/Auditing/Auditing.Core/Enums/AuditOperation.cs b/src/framework/Auditing/Auditing.Core/Enums/AuditOperation.cs new file mode 100644 index 000000000..a5e99f175 --- /dev/null +++ b/src/framework/Auditing/Auditing.Core/Enums/AuditOperation.cs @@ -0,0 +1,8 @@ +namespace FSH.Framework.Auditing.Core.Enums; +public enum AuditOperation +{ + None = 0, + Create = 1, + Update = 2, + Delete = 3 +} diff --git a/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs b/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs new file mode 100644 index 000000000..969e1f524 --- /dev/null +++ b/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs @@ -0,0 +1,14 @@ +using FSH.Framework.Auditing.Core.Dtos; +using MediatR; + +namespace FSH.Framework.Auditing.Core.Events; + +public class AuditPublishedEvent : INotification +{ + public IReadOnlyCollection Trails { get; } + + public AuditPublishedEvent(IReadOnlyCollection trails) + { + Trails = trails; + } +} diff --git a/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj b/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj new file mode 100644 index 000000000..218a24767 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj @@ -0,0 +1,19 @@ + + + FSH.Framework.Auditing.Endpoints + FSH.Framework.Auditing.Endpoints + + + + net9.0 + enable + enable + + + + + + + + + diff --git a/src/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits/GetUserAuditTrailEndpoint.cs similarity index 81% rename from src/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs rename to src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits/GetUserAuditTrailEndpoint.cs index 78ca37942..59b1724c0 100644 --- a/src/framework/Infrastructure/Identity/Audit/Endpoints/GetUserAuditTrailEndpoint.cs +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits/GetUserAuditTrailEndpoint.cs @@ -1,10 +1,10 @@ -using FSH.Framework.Core.Audit; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Infrastructure.Identity.Audit.Endpoints; +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserAudits; public static class GetUserAuditTrailEndpoint { diff --git a/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj b/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj new file mode 100644 index 000000000..d29c813a4 --- /dev/null +++ b/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj @@ -0,0 +1,16 @@ + + + FSH.Framework.Auditing.Infrastructure + FSH.Framework.Auditing.Infrastructure + + + net9.0 + enable + enable + + + + + + + diff --git a/src/framework/Auditing/Events/AuditPublishedEventHandler.cs b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs similarity index 88% rename from src/framework/Auditing/Events/AuditPublishedEventHandler.cs rename to src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs index 0e23cf482..8c43ec988 100644 --- a/src/framework/Auditing/Events/AuditPublishedEventHandler.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs @@ -1,9 +1,10 @@ -using FSH.Framework.Auditing.Abstractions; +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Auditing.Core.Events; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -namespace FSH.Framework.Auditing.Events; +namespace FSH.Framework.Auditing.Infrastructure.Handlers; public class AuditPublishedEventHandler( ILogger logger, diff --git a/src/framework/Auditing/Interceptors/AuditInterceptor.cs b/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs similarity index 75% rename from src/framework/Auditing/Interceptors/AuditInterceptor.cs rename to src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs index c8e501741..886d59484 100644 --- a/src/framework/Auditing/Interceptors/AuditInterceptor.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs @@ -1,9 +1,6 @@ -using System.Collections.ObjectModel; -using FSH.Framework.Auditing.Dtos; -using FSH.Framework.Auditing.Enums; -using FSH.Framework.Auditing.Events; -using FSH.Framework.Auditing.Mappings; -using FSH.Framework.Auditing.Models; +using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Auditing.Core.Enums; +using FSH.Framework.Auditing.Core.Events; using FSH.Framework.Core.Domain; using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.ExecutionContext; @@ -12,10 +9,9 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; -namespace FSH.Framework.Auditing.Interceptors; +namespace FSH.Framework.Auditing.Infrastructure.Interceptors; public class AuditInterceptor(ICurrentUser currentUser, TimeProvider timeProvider, IPublisher publisher) : SaveChangesInterceptor { - public override ValueTask SavedChangesAsync(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = default) { return base.SavedChangesAsync(eventData, result, cancellationToken); @@ -37,15 +33,15 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData) { if (eventData.Context == null) return; eventData.Context.ChangeTracker.DetectChanges(); - var trails = new List(); + var trails = new List(); var utcNow = timeProvider.GetUtcNow(); foreach (var entry in eventData.Context.ChangeTracker.Entries().Where(x => x.State is EntityState.Added or EntityState.Deleted or EntityState.Modified).ToList()) { var userId = currentUser.GetUserId(); - var trail = new TrailDto() + var audit = new AuditTrail() { Id = Guid.NewGuid(), - TableName = entry.Entity.GetType().Name, + EntityName = entry.Entity.GetType().Name, UserId = userId, DateTime = utcNow }; @@ -59,20 +55,20 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData) string propertyName = property.Metadata.Name; if (property.Metadata.IsPrimaryKey()) { - trail.KeyValues[propertyName] = property.CurrentValue; + audit.KeyValues[propertyName] = property.CurrentValue; continue; } switch (entry.State) { case EntityState.Added: - trail.Type = TrailType.Create; - trail.NewValues[propertyName] = property.CurrentValue; + audit.Operation = AuditOperation.Create; + audit.NewValues[propertyName] = property.CurrentValue; break; case EntityState.Deleted: - trail.Type = TrailType.Delete; - trail.OldValues[propertyName] = property.OriginalValue; + audit.Operation = AuditOperation.Delete; + audit.OldValues[propertyName] = property.OriginalValue; break; case EntityState.Modified: @@ -80,17 +76,17 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData) { if (entry.Entity is ISoftDeletable && property.OriginalValue == null && property.CurrentValue != null) { - trail.ModifiedProperties.Add(propertyName); - trail.Type = TrailType.Delete; - trail.OldValues[propertyName] = property.OriginalValue; - trail.NewValues[propertyName] = property.CurrentValue; + audit.ModifiedProperties.Add(propertyName); + audit.Operation = AuditOperation.Delete; + audit.OldValues[propertyName] = property.OriginalValue; + audit.NewValues[propertyName] = property.CurrentValue; } else if (property.OriginalValue?.Equals(property.CurrentValue) == false) { - trail.ModifiedProperties.Add(propertyName); - trail.Type = TrailType.Update; - trail.OldValues[propertyName] = property.OriginalValue; - trail.NewValues[propertyName] = property.CurrentValue; + audit.ModifiedProperties.Add(propertyName); + audit.Operation = AuditOperation.Update; + audit.OldValues[propertyName] = property.OriginalValue; + audit.NewValues[propertyName] = property.CurrentValue; } else { @@ -101,15 +97,10 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData) } } - trails.Add(trail); + trails.Add(audit); } if (trails.Count == 0) return; - var auditTrails = new Collection(); - foreach (var trail in trails) - { - auditTrails.Add(trail.ToAuditTrail()); - } - await publisher.Publish(new AuditPublishedEvent(auditTrails)); + await publisher.Publish(new AuditPublishedEvent(trails)); } public void UpdateEntities(DbContext? context) diff --git a/src/framework/Auditing/Services/AuditService.cs b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs similarity index 73% rename from src/framework/Auditing/Services/AuditService.cs rename to src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs index 018ec962a..f9944feb2 100644 --- a/src/framework/Auditing/Services/AuditService.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs @@ -1,8 +1,8 @@ -using FSH.Framework.Auditing.Abstractions; -using FSH.Framework.Auditing.Models; +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Auditing.Core.Dtos; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Auditing.Services; +namespace FSH.Framework.Auditing.Infrastructure.Services; public class AuditService(IAuditTrailDbContext context) : IAuditService { public async Task> GetUserTrailsAsync(Guid userId) diff --git a/src/framework/Auditing/Dtos/TrailDto.cs b/src/framework/Auditing/Dtos/TrailDto.cs deleted file mode 100644 index 33b2d203a..000000000 --- a/src/framework/Auditing/Dtos/TrailDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.ObjectModel; -using FSH.Framework.Auditing.Enums; - -namespace FSH.Framework.Auditing.Dtos; -public class TrailDto -{ - public Guid Id { get; set; } - public DateTimeOffset DateTime { get; set; } - public Guid UserId { get; set; } - public Dictionary KeyValues { get; } = []; - public Dictionary OldValues { get; } = []; - public Dictionary NewValues { get; } = []; - public Collection ModifiedProperties { get; } = []; - public TrailType Type { get; set; } - public string? TableName { get; set; } -} diff --git a/src/framework/Auditing/Enums/TrailType.cs b/src/framework/Auditing/Enums/TrailType.cs deleted file mode 100644 index 5c0d1a909..000000000 --- a/src/framework/Auditing/Enums/TrailType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace FSH.Framework.Auditing.Enums; -public enum TrailType -{ - None = 0, - Create = 1, - Update = 2, - Delete = 3 -} diff --git a/src/framework/Auditing/Events/AuditPublishedEvent.cs b/src/framework/Auditing/Events/AuditPublishedEvent.cs deleted file mode 100644 index 8d0255670..000000000 --- a/src/framework/Auditing/Events/AuditPublishedEvent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.ObjectModel; -using FSH.Framework.Auditing.Models; -using MediatR; - -namespace FSH.Framework.Auditing.Events; -public class AuditPublishedEvent : INotification -{ - public AuditPublishedEvent(Collection? trails) - { - Trails = trails; - } - public Collection? Trails { get; } -} diff --git a/src/framework/Auditing/Mappings/TrailMapping.cs b/src/framework/Auditing/Mappings/TrailMapping.cs deleted file mode 100644 index b7985ab64..000000000 --- a/src/framework/Auditing/Mappings/TrailMapping.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Text.Json; -using FSH.Framework.Auditing.Dtos; -using FSH.Framework.Auditing.Models; - -namespace FSH.Framework.Auditing.Mappings; - -public static class TrailMapping -{ - private static readonly JsonSerializerOptions SerializerOptions = new() - { - WriteIndented = false, - }; - - public static AuditTrail ToAuditTrail(this TrailDto trail) - { - return new AuditTrail - { - Id = Guid.NewGuid(), - UserId = trail.UserId, - Operation = trail.Type.ToString(), - Entity = trail.TableName, - DateTime = trail.DateTime, - PrimaryKey = JsonSerializer.Serialize(trail.KeyValues, SerializerOptions), - PreviousValues = trail.OldValues.Count == 0 ? null : JsonSerializer.Serialize(trail.OldValues, SerializerOptions), - NewValues = trail.NewValues.Count == 0 ? null : JsonSerializer.Serialize(trail.NewValues, SerializerOptions), - ModifiedProperties = trail.ModifiedProperties.Count == 0 ? null : JsonSerializer.Serialize(trail.ModifiedProperties, SerializerOptions) - }; - } -} diff --git a/src/framework/Auditing/Models/AuditTrail.cs b/src/framework/Auditing/Models/AuditTrail.cs deleted file mode 100644 index 99e8bde1c..000000000 --- a/src/framework/Auditing/Models/AuditTrail.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace FSH.Framework.Auditing.Models; -public class AuditTrail -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public string? Operation { get; set; } - public string? Entity { get; set; } - public DateTimeOffset DateTime { get; set; } - public string? PreviousValues { get; set; } - public string? NewValues { get; set; } - public string? ModifiedProperties { get; set; } - public string? PrimaryKey { get; set; } -} diff --git a/src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs deleted file mode 100644 index 900c15395..000000000 --- a/src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsCommand.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FSH.Framework.Core.Identity.Roles.Features.UpdatePermissions; -public class UpdatePermissionsCommand -{ - public string RoleId { get; set; } = default!; - public List Permissions { get; set; } = default!; -} diff --git a/src/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs b/src/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs deleted file mode 100644 index ee747c7ba..000000000 --- a/src/framework/Core/Identity/Tokens/Features/Generate/TokenGenerationCommand.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.ComponentModel; -using FluentValidation; - -namespace FSH.Framework.Core.Identity.Tokens.Features.Generate; -public record TokenGenerationCommand( - [property: DefaultValue(TenantConstants.Root.EmailAddress)] string Email, - [property: DefaultValue(TenantConstants.DefaultPassword)] string Password); - -public class GenerateTokenValidator : AbstractValidator -{ - public GenerateTokenValidator() - { - RuleFor(p => p.Email).Cascade(CascadeMode.Stop).NotEmpty().EmailAddress(); - - RuleFor(p => p.Password).Cascade(CascadeMode.Stop).NotEmpty(); - } -} diff --git a/src/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs b/src/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs deleted file mode 100644 index 34f3fadb8..000000000 --- a/src/framework/Core/Identity/Users/Features/AssignUserRole/AssignUserRoleCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FSH.Framework.Core.Identity.Users.Dtos; - -namespace FSH.Framework.Core.Identity.Users.Features.AssignUserRole; -public class AssignUserRoleCommand -{ - public List UserRoles { get; set; } = new(); -} diff --git a/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs b/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs deleted file mode 100644 index 82abe1323..000000000 --- a/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace FSH.Framework.Core.Identity.Users.Features.ChangePassword; -public class ChangePasswordCommand -{ - public string Password { get; set; } = default!; - public string NewPassword { get; set; } = default!; - public string ConfirmNewPassword { get; set; } = default!; -} diff --git a/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs b/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs deleted file mode 100644 index 9d52f7885..000000000 --- a/src/framework/Core/Identity/Users/Features/ChangePassword/ChangePasswordValidator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Core.Identity.Users.Features.ChangePassword; -public class ChangePasswordValidator : AbstractValidator -{ - public ChangePasswordValidator() - { - RuleFor(p => p.Password) - .NotEmpty(); - - RuleFor(p => p.NewPassword) - .NotEmpty(); - - RuleFor(p => p.ConfirmNewPassword) - .Equal(p => p.NewPassword) - .WithMessage("passwords do not match."); - } -} diff --git a/src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs b/src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs deleted file mode 100644 index 967539ae7..000000000 --- a/src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserResponse.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Core.Identity.Users.Features.RegisterUser; -public record RegisterUserResponse(string UserId); diff --git a/src/framework/Core/Storage/File/Features/FileUploadCommand.cs b/src/framework/Core/Storage/File/Features/FileUploadCommand.cs deleted file mode 100644 index c4e5cb0e5..000000000 --- a/src/framework/Core/Storage/File/Features/FileUploadCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using MediatR; - -namespace FSH.Framework.Core.Storage.File.Features; - -public class FileUploadCommand : IRequest -{ - public string Name { get; set; } = default!; - public string Extension { get; set; } = default!; - public string Data { get; set; } = default!; -} - diff --git a/src/framework/Core/Storage/File/Features/FileUploadResponse.cs b/src/framework/Core/Storage/File/Features/FileUploadResponse.cs deleted file mode 100644 index f3af35deb..000000000 --- a/src/framework/Core/Storage/File/Features/FileUploadResponse.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace FSH.Framework.Core.Storage.File.Features; - -public class FileUploadResponse -{ - public Uri Url { get; set; } = default!; -} - diff --git a/src/framework/Core/Storage/File/Features/FileUploadValidator.cs b/src/framework/Core/Storage/File/Features/FileUploadValidator.cs deleted file mode 100644 index c064cf93f..000000000 --- a/src/framework/Core/Storage/File/Features/FileUploadValidator.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Core.Storage.File.Features; - -public class FileUploadRequestValidator : AbstractValidator -{ - public FileUploadRequestValidator() - { - RuleFor(p => p.Name) - .NotEmpty() - .MaximumLength(150); - - RuleFor(p => p.Extension) - .NotEmpty() - .MaximumLength(5); - - RuleFor(p => p.Data) - .NotEmpty(); - } -} - diff --git a/src/framework/Core/Storage/File/FileType.cs b/src/framework/Core/Storage/File/FileType.cs deleted file mode 100644 index 267968aaa..000000000 --- a/src/framework/Core/Storage/File/FileType.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.ComponentModel; - -namespace FSH.Framework.Core.Storage.File; - -public enum FileType -{ - [Description(".jpg,.png,.jpeg")] - Image -} diff --git a/src/framework/Core/Storage/FileType.cs b/src/framework/Core/Storage/FileType.cs new file mode 100644 index 000000000..6abc1305b --- /dev/null +++ b/src/framework/Core/Storage/FileType.cs @@ -0,0 +1,24 @@ +namespace FSH.Framework.Core.Storage; +public enum FileType +{ + Image, + Document, + Pdf +} + +public class FileValidationRules +{ + public IReadOnlyList AllowedExtensions { get; init; } = Array.Empty(); + public int MaxSizeInMB { get; init; } = 5; +} + +public static class FileTypeMetadata +{ + public static FileValidationRules GetRules(FileType type) => + type switch + { + FileType.Image => new() { AllowedExtensions = [".jpg", ".jpeg", ".png"], MaxSizeInMB = 5 }, + FileType.Pdf => new() { AllowedExtensions = [".pdf"], MaxSizeInMB = 10 }, + _ => throw new NotSupportedException($"Unsupported file type: {type}") + }; +} diff --git a/src/framework/Core/Storage/FileUploadRequest.cs b/src/framework/Core/Storage/FileUploadRequest.cs new file mode 100644 index 000000000..086b3bd70 --- /dev/null +++ b/src/framework/Core/Storage/FileUploadRequest.cs @@ -0,0 +1,7 @@ +namespace FSH.Framework.Core.Storage; +public class FileUploadRequest +{ + public string FileName { get; init; } = default!; + public string ContentType { get; init; } = default!; + public IReadOnlyList Data { get; init; } = Array.Empty(); +} diff --git a/src/framework/Core/Storage/FileUploadRequestValidator.cs b/src/framework/Core/Storage/FileUploadRequestValidator.cs new file mode 100644 index 000000000..6fcd8381b --- /dev/null +++ b/src/framework/Core/Storage/FileUploadRequestValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; + +namespace FSH.Framework.Core.Storage; + +public class FileUploadRequestValidator : AbstractValidator +{ + public FileUploadRequestValidator(FileType fileType) + { + var rules = FileTypeMetadata.GetRules(fileType); + + RuleFor(x => x.FileName) + .NotEmpty() + .Must(file => rules.AllowedExtensions.Any(ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) + .WithMessage($"Only these extensions are allowed: {string.Join(", ", rules.AllowedExtensions)}"); + + RuleFor(x => x.Data) + .NotEmpty() + .Must(data => data.Count <= rules.MaxSizeInMB * 1024 * 1024) + .WithMessage($"File must be <= {rules.MaxSizeInMB} MB."); + } +} diff --git a/src/framework/Core/Storage/IStorageService.cs b/src/framework/Core/Storage/IStorageService.cs index 5e13d6dde..b4635fdaa 100644 --- a/src/framework/Core/Storage/IStorageService.cs +++ b/src/framework/Core/Storage/IStorageService.cs @@ -1,12 +1,10 @@ -using FSH.Framework.Core.Storage.File; -using FSH.Framework.Core.Storage.File.Features; - -namespace FSH.Framework.Core.Storage; - +namespace FSH.Framework.Core.Storage; public interface IStorageService { - public Task UploadAsync(FileUploadCommand? request, FileType supportedFileType, CancellationToken cancellationToken = default) - where T : class; + Task UploadAsync( + FileUploadRequest request, + FileType fileType, + CancellationToken cancellationToken = default) where T : class; - public void Remove(Uri? path); + Task RemoveAsync(string path, CancellationToken cancellationToken = default); } diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 5bec34c1e..c9352cdb5 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -7,10 +7,28 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{60DF219E-E1EB-428E-BB1F-F0342D42699F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing", "Auditing\Auditing.csproj", "{AB2C0DA8-74CA-42AB-BD50-D0162463742A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application", "Application\Application.csproj", "{63773336-64B9-4A55-B1EA-EEF18BDF73D9}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{15EA2212-0958-4415-AA37-116F2A47F23F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tenant", "Tenant", "{24E922E3-8C91-43A1-A110-D8F5276566BA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Core", "Identity\Identity.Core\Identity.Core.csproj", "{D59824CA-B55C-4D45-B485-771B31FE7575}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Infrastructure", "Identity\Identity.Infrastructure\Identity.Infrastructure.csproj", "{8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Endpoints", "Identity\Identity.Endpoints\Identity.Endpoints.csproj", "{CE91E947-D5FA-499A-BB28-373CB8209813}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auditing", "Auditing", "{E5141F38-2D08-44DA-9A6C-B96890515168}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Core", "Auditing\Auditing.Core\Auditing.Core.csproj", "{0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Infrastructure", "Auditing\Auditing.Infrastructure\Auditing.Infrastructure.csproj", "{C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Endpoints", "Auditing\Auditing.Endpoints\Auditing.Endpoints.csproj", "{C8DCA061-E4D6-414F-9053-0723B6764D71}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{09380C15-F138-4305-A595-F4C7E16B6E78}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -25,16 +43,48 @@ Global {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Debug|Any CPU.Build.0 = Debug|Any CPU {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Release|Any CPU.ActiveCfg = Release|Any CPU {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Release|Any CPU.Build.0 = Release|Any CPU - {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AB2C0DA8-74CA-42AB-BD50-D0162463742A}.Release|Any CPU.Build.0 = Release|Any CPU {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Release|Any CPU.Build.0 = Release|Any CPU + {D59824CA-B55C-4D45-B485-771B31FE7575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D59824CA-B55C-4D45-B485-771B31FE7575}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D59824CA-B55C-4D45-B485-771B31FE7575}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D59824CA-B55C-4D45-B485-771B31FE7575}.Release|Any CPU.Build.0 = Release|Any CPU + {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Release|Any CPU.Build.0 = Release|Any CPU + {CE91E947-D5FA-499A-BB28-373CB8209813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE91E947-D5FA-499A-BB28-373CB8209813}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE91E947-D5FA-499A-BB28-373CB8209813}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE91E947-D5FA-499A-BB28-373CB8209813}.Release|Any CPU.Build.0 = Release|Any CPU + {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Release|Any CPU.Build.0 = Release|Any CPU + {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Release|Any CPU.Build.0 = Release|Any CPU + {C8DCA061-E4D6-414F-9053-0723B6764D71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8DCA061-E4D6-414F-9053-0723B6764D71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8DCA061-E4D6-414F-9053-0723B6764D71}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8DCA061-E4D6-414F-9053-0723B6764D71}.Release|Any CPU.Build.0 = Release|Any CPU + {09380C15-F138-4305-A595-F4C7E16B6E78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09380C15-F138-4305-A595-F4C7E16B6E78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D59824CA-B55C-4D45-B485-771B31FE7575} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {CE91E947-D5FA-499A-BB28-373CB8209813} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2} = {E5141F38-2D08-44DA-9A6C-B96890515168} + {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786} = {E5141F38-2D08-44DA-9A6C-B96890515168} + {C8DCA061-E4D6-414F-9053-0723B6764D71} = {E5141F38-2D08-44DA-9A6C-B96890515168} + EndGlobalSection EndGlobal diff --git a/src/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs b/src/framework/Identity/Identity.Core/Abstractions/ICurrentUserInitializer.cs similarity index 74% rename from src/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs rename to src/framework/Identity/Identity.Core/Abstractions/ICurrentUserInitializer.cs index 2342d75b8..161fdde45 100644 --- a/src/framework/Core/Identity/Users/Abstractions/ICurrentUserInitializer.cs +++ b/src/framework/Identity/Identity.Core/Abstractions/ICurrentUserInitializer.cs @@ -1,6 +1,6 @@ using System.Security.Claims; -namespace FSH.Framework.Core.Identity.Users.Abstractions; +namespace FSH.Framework.Identity.Core.Abstractions; public interface ICurrentUserInitializer { void SetCurrentUser(ClaimsPrincipal user); diff --git a/src/framework/Core/Identity/Users/Abstractions/IUserService.cs b/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs similarity index 98% rename from src/framework/Core/Identity/Users/Abstractions/IUserService.cs rename to src/framework/Identity/Identity.Core/Abstractions/IUserService.cs index 95fbf9f57..e22ef248c 100644 --- a/src/framework/Core/Identity/Users/Abstractions/IUserService.cs +++ b/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs @@ -7,6 +7,7 @@ using FSH.Framework.Core.Identity.Users.Features.ResetPassword; using FSH.Framework.Core.Identity.Users.Features.ToggleUserStatus; using FSH.Framework.Core.Identity.Users.Features.UpdateUser; +using FSH.Framework.Identity.Core.Dtos; namespace FSH.Framework.Core.Identity.Users.Abstractions; public interface IUserService diff --git a/src/framework/Core/Identity/Users/Dtos/UserDetail.cs b/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs similarity index 88% rename from src/framework/Core/Identity/Users/Dtos/UserDetail.cs rename to src/framework/Identity/Identity.Core/Dtos/UserDetail.cs index 23941ad86..92b2c5cf3 100644 --- a/src/framework/Core/Identity/Users/Dtos/UserDetail.cs +++ b/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Identity.Users.Dtos; +namespace FSH.Framework.Identity.Core.Dtos; public class UserDetail { public Guid Id { get; set; } diff --git a/src/framework/Core/Identity/Users/Dtos/UserRoleDetail.cs b/src/framework/Identity/Identity.Core/Dtos/UserRoleDetail.cs similarity index 100% rename from src/framework/Core/Identity/Users/Dtos/UserRoleDetail.cs rename to src/framework/Identity/Identity.Core/Dtos/UserRoleDetail.cs diff --git a/src/framework/Identity/Identity.Core/Identity.Core.csproj b/src/framework/Identity/Identity.Core/Identity.Core.csproj new file mode 100644 index 000000000..6cc091ce7 --- /dev/null +++ b/src/framework/Identity/Identity.Core/Identity.Core.csproj @@ -0,0 +1,12 @@ + + + FSH.Framework.Identity.Core + FSH.Framework.Identity.Core + + + net9.0 + enable + enable + + + diff --git a/src/framework/Core/Identity/Roles/IRoleService.cs b/src/framework/Identity/Identity.Core/Roles/IRoleService.cs similarity index 68% rename from src/framework/Core/Identity/Roles/IRoleService.cs rename to src/framework/Identity/Identity.Core/Roles/IRoleService.cs index dca61839a..43339694b 100644 --- a/src/framework/Core/Identity/Roles/IRoleService.cs +++ b/src/framework/Identity/Identity.Core/Roles/IRoleService.cs @@ -1,7 +1,4 @@ -using FSH.Framework.Core.Identity.Roles.Features.CreateOrUpdateRole; -using FSH.Framework.Core.Identity.Roles.Features.UpdatePermissions; - -namespace FSH.Framework.Core.Identity.Roles; +namespace FSH.Framework.Identity.Core.Roles; public interface IRoleService { diff --git a/src/framework/Core/Identity/Roles/RoleDto.cs b/src/framework/Identity/Identity.Core/Roles/RoleDto.cs similarity index 81% rename from src/framework/Core/Identity/Roles/RoleDto.cs rename to src/framework/Identity/Identity.Core/Roles/RoleDto.cs index 0a0fc7559..75ef78631 100644 --- a/src/framework/Core/Identity/Roles/RoleDto.cs +++ b/src/framework/Identity/Identity.Core/Roles/RoleDto.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Identity.Roles; +namespace FSH.Framework.Identity.Core.Roles; public class RoleDto { diff --git a/src/framework/Core/Identity/Tokens/ITokenService.cs b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs similarity index 91% rename from src/framework/Core/Identity/Tokens/ITokenService.cs rename to src/framework/Identity/Identity.Core/Tokens/ITokenService.cs index 86665ec81..72359a31e 100644 --- a/src/framework/Core/Identity/Tokens/ITokenService.cs +++ b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs @@ -2,7 +2,7 @@ using FSH.Framework.Core.Identity.Tokens.Features.Refresh; using FSH.Framework.Core.Identity.Tokens.Models; -namespace FSH.Framework.Core.Identity.Tokens; +namespace FSH.Framework.Identity.Core.Tokens; public interface ITokenService { Task GenerateTokenAsync(TokenGenerationCommand request, string ipAddress, CancellationToken cancellationToken); diff --git a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj new file mode 100644 index 000000000..334864d8b --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj @@ -0,0 +1,19 @@ + + + FSH.Framework.Identity.Endpoints + FSH.Framework.Identity.Endpoints + + + net9.0 + enable + enable + + + + + + + + + + diff --git a/src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs similarity index 70% rename from src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs index 5774c40ae..f64001506 100644 --- a/src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Identity.Roles.Features.CreateOrUpdateRole; +namespace FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; public class CreateOrUpdateRoleCommand { diff --git a/src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs similarity index 77% rename from src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs rename to src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs index 68f452666..a36d583ab 100644 --- a/src/framework/Core/Identity/Roles/Features/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs @@ -1,6 +1,6 @@ using FluentValidation; -namespace FSH.Framework.Core.Identity.Roles.Features.CreateOrUpdateRole; +namespace FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; public class CreateOrUpdateRoleValidator : AbstractValidator { diff --git a/src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs new file mode 100644 index 000000000..d499f153c --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs @@ -0,0 +1,14 @@ +namespace FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; + +public class UpdatePermissionsCommand +{ + /// + /// The ID of the role to update. + /// + public string RoleId { get; init; } = default!; + + /// + /// The list of permissions to assign to the role. + /// + public IReadOnlyList Permissions { get; init; } = Array.Empty(); +} diff --git a/src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs similarity index 79% rename from src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs rename to src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs index 34b0b7f01..7536d1c29 100644 --- a/src/framework/Core/Identity/Roles/Features/UpdatePermissions/UpdatePermissionsValidator.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs @@ -1,6 +1,6 @@ using FluentValidation; -namespace FSH.Framework.Core.Identity.Roles.Features.UpdatePermissions; +namespace FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; public class UpdatePermissionsValidator : AbstractValidator { public UpdatePermissionsValidator() diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs new file mode 100644 index 000000000..151d67339 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs @@ -0,0 +1,14 @@ +using FluentValidation; + +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; +public record TokenGenerationCommand(string Email, string Password); + +public class GenerateTokenValidator : AbstractValidator +{ + public GenerateTokenValidator() + { + RuleFor(p => p.Email).Cascade(CascadeMode.Stop).NotEmpty().EmailAddress(); + + RuleFor(p => p.Password).Cascade(CascadeMode.Stop).NotEmpty(); + } +} diff --git a/src/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenCommand.cs similarity index 85% rename from src/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenCommand.cs index 8fc45b8d2..8e55cd6a7 100644 --- a/src/framework/Core/Identity/Tokens/Features/Refresh/RefreshTokenCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenCommand.cs @@ -1,6 +1,6 @@ using FluentValidation; -namespace FSH.Framework.Core.Identity.Tokens.Features.Refresh; +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Refresh; public record RefreshTokenCommand(string Token, string RefreshToken); public class RefreshTokenValidator : AbstractValidator diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs new file mode 100644 index 000000000..491777145 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs @@ -0,0 +1,11 @@ +using FSH.Framework.Core.Identity.Users.Dtos; + +namespace FSH.Framework.Identity.Endpoints.v1.Users.AssignUserRole; + +public class AssignUserRoleCommand +{ + /// + /// A list of user-role assignment entries. + /// + public IReadOnlyList UserRoles { get; init; } = Array.Empty(); +} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs new file mode 100644 index 000000000..a6b36be79 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs @@ -0,0 +1,13 @@ +namespace FSH.Framework.Identity.Endpoints.v1.Users.ChangePassword; + +public class ChangePasswordCommand +{ + /// The user's current password. + public string Password { get; init; } = default!; + + /// The new password the user wants to set. + public string NewPassword { get; init; } = default!; + + /// Confirmation of the new password. + public string ConfirmNewPassword { get; init; } = default!; +} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs new file mode 100644 index 000000000..99ba3ad85 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs @@ -0,0 +1,23 @@ +using FluentValidation; + +namespace FSH.Framework.Identity.Endpoints.v1.Users.ChangePassword; + +public class ChangePasswordValidator : AbstractValidator +{ + public ChangePasswordValidator() + { + RuleFor(p => p.Password) + .NotEmpty() + .WithMessage("Current password is required."); + + RuleFor(p => p.NewPassword) + .NotEmpty() + .WithMessage("New password is required.") + .NotEqual(p => p.Password) + .WithMessage("New password must be different from the current password."); + + RuleFor(p => p.ConfirmNewPassword) + .Equal(p => p.NewPassword) + .WithMessage("Passwords do not match."); + } +} diff --git a/src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs similarity index 55% rename from src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs index 5419a554f..b2cc0e19b 100644 --- a/src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Identity.Users.Features.ForgotPassword; +namespace FSH.Framework.Identity.Endpoints.v1.Users.ForgotPassword; public class ForgotPasswordCommand { public string Email { get; set; } = default!; diff --git a/src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs similarity index 79% rename from src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs rename to src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs index 2df57f5be..f8418a60e 100644 --- a/src/framework/Core/Identity/Users/Features/ForgotPassword/ForgotPasswordValidator.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs @@ -1,6 +1,6 @@ using FluentValidation; -namespace FSH.Framework.Core.Identity.Users.Features.ForgotPassword; +namespace FSH.Framework.Identity.Endpoints.v1.Users.ForgotPassword; public class ForgotPasswordValidator : AbstractValidator { public ForgotPasswordValidator() diff --git a/src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs similarity index 89% rename from src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs index 34089d047..c18e4c72e 100644 --- a/src/framework/Core/Identity/Users/Features/RegisterUser/RegisterUserCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; using MediatR; -namespace FSH.Framework.Core.Identity.Users.Features.RegisterUser; +namespace FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; public class RegisterUserCommand : IRequest { public string FirstName { get; set; } = default!; diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs new file mode 100644 index 000000000..dee053912 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; +public record RegisterUserResponse(string UserId); diff --git a/src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs similarity index 73% rename from src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs index 244aff2e9..33c4e3c39 100644 --- a/src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Identity.Users.Features.ResetPassword; +namespace FSH.Framework.Identity.Endpoints.v1.Users.ResetPassword; public class ResetPasswordCommand { public string Email { get; set; } = default!; diff --git a/src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs similarity index 81% rename from src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs rename to src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs index 414190565..8ee889e44 100644 --- a/src/framework/Core/Identity/Users/Features/ResetPassword/ResetPasswordValidator.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs @@ -1,6 +1,6 @@ using FluentValidation; -namespace FSH.Framework.Core.Identity.Users.Features.ResetPassword; +namespace FSH.Framework.Identity.Endpoints.v1.Users.ResetPassword; public class ResetPasswordValidator : AbstractValidator { diff --git a/src/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs similarity index 62% rename from src/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs index 8b3697293..b049fc54e 100644 --- a/src/framework/Core/Identity/Users/Features/ToggleUserStatus/ToggleUserStatusCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Identity.Users.Features.ToggleUserStatus; +namespace FSH.Framework.Identity.Endpoints.v1.Users.ToggleUserStatus; public class ToggleUserStatusCommand { public bool ActivateUser { get; set; } diff --git a/src/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs similarity index 54% rename from src/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs index 470516218..8a118b815 100644 --- a/src/framework/Core/Identity/Users/Features/UpdateUser/UpdateUserCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs @@ -1,14 +1,13 @@ -using FSH.Framework.Core.Storage.File.Features; -using MediatR; +using FSH.Framework.Core.Storage; -namespace FSH.Framework.Core.Identity.Users.Features.UpdateUser; -public class UpdateUserCommand : IRequest +namespace FSH.Framework.Identity.Endpoints.v1.Users.UpdateUser; +public class UpdateUserCommand { public string Id { get; set; } = default!; public string? FirstName { get; set; } public string? LastName { get; set; } public string? PhoneNumber { get; set; } public string? Email { get; set; } - public FileUploadCommand? Image { get; set; } + public FileUploadRequest? Image { get; set; } public bool DeleteCurrentImage { get; set; } } diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs new file mode 100644 index 000000000..81b0e1752 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs @@ -0,0 +1,40 @@ +using FluentValidation; +using FSH.Framework.Core.Storage; + +namespace FSH.Framework.Identity.Endpoints.v1.Users.UpdateUser; +public class UpdateUserCommandValidator : AbstractValidator +{ + public UpdateUserCommandValidator() + { + RuleFor(x => x.Id) + .NotEmpty() + .WithMessage("User ID is required."); + + RuleFor(x => x.FirstName) + .MaximumLength(50) + .When(x => !string.IsNullOrWhiteSpace(x.FirstName)); + + RuleFor(x => x.LastName) + .MaximumLength(50) + .When(x => !string.IsNullOrWhiteSpace(x.LastName)); + + RuleFor(x => x.PhoneNumber) + .MaximumLength(15) + .When(x => !string.IsNullOrWhiteSpace(x.PhoneNumber)); + + RuleFor(x => x.Email) + .EmailAddress() + .When(x => !string.IsNullOrWhiteSpace(x.Email)); + + When(x => x.Image is not null, () => + { + RuleFor(x => x.Image!) + .SetValidator(new FileUploadRequestValidator(FileType.Image)); + }); + + // Prevent deleting and uploading image at the same time + RuleFor(x => x) + .Must(x => !(x.DeleteCurrentImage && x.Image is not null)) + .WithMessage("You cannot upload a new image and delete the current one simultaneously."); + } +} diff --git a/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs similarity index 86% rename from src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs rename to src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs index 8903b660e..162bbcb32 100644 --- a/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationHandler.cs +++ b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs @@ -1,9 +1,6 @@ using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Starter.Shared.Authorization; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -namespace FSH.Framework.Infrastructure.Auth.Policy; +namespace FSH.Framework.Identity.Infrastructure.Authorization; public sealed class RequiredPermissionAuthorizationHandler(IUserService userService) : AuthorizationHandler { protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement) diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj new file mode 100644 index 000000000..48c7c4f40 --- /dev/null +++ b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -0,0 +1,15 @@ + + + FSH.Framework.Identity.Infrastructure + FSH.Framework.Identity.Infrastructure + + + net9.0 + enable + enable + + + + + + diff --git a/src/framework/Infrastructure/Infrastructure.csproj b/src/framework/Infrastructure/Infrastructure.csproj index cad185ec2..b258efd7c 100644 --- a/src/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Infrastructure/Infrastructure.csproj @@ -58,5 +58,8 @@ + + + diff --git a/src/framework/Infrastructure/Storage/Files/Extension.cs b/src/framework/Infrastructure/Storage/Files/Extension.cs deleted file mode 100644 index 6699f126d..000000000 --- a/src/framework/Infrastructure/Storage/Files/Extension.cs +++ /dev/null @@ -1,25 +0,0 @@ -using FSH.Framework.Core.Storage; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.FileProviders; - -namespace FSH.Framework.Infrastructure.Storage.Files; - -internal static class Extension -{ - internal static IServiceCollection ConfigureFileStorage(this IServiceCollection services) - { - ArgumentNullException.ThrowIfNull(services); - services.AddTransient(); - - return services; - } - - internal static IApplicationBuilder UseFileStorage(this IApplicationBuilder app) => - app.UseStaticFiles(new StaticFileOptions() - { - FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Files")), - RequestPath = new PathString("/Files") - }); -} diff --git a/src/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs b/src/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs deleted file mode 100644 index 16b786da6..000000000 --- a/src/framework/Infrastructure/Storage/Files/LocalFileStorageService.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; -using FSH.Framework.Core.Origin; -using FSH.Framework.Core.Storage; -using FSH.Framework.Core.Storage.File; -using FSH.Framework.Core.Storage.File.Features; -using FSH.Framework.Infrastructure.Common.Extensions; -using Microsoft.Extensions.Options; -namespace FSH.Framework.Infrastructure.Storage.Files -{ - public class LocalFileStorageService(IOptions originSettings) : IStorageService - { - public async Task UploadAsync(FileUploadCommand? request, FileType supportedFileType, CancellationToken cancellationToken = default) - where T : class - { - if (request == null || request.Data == null) - { - return null!; - } - - if (request.Extension is null || !supportedFileType.GetDescriptionList().Contains(request.Extension.ToLower(System.Globalization.CultureInfo.CurrentCulture))) - throw new InvalidOperationException("File Format Not Supported."); - if (request.Name is null) - throw new InvalidOperationException("Name is required."); - - string base64Data = Regex.Match(request.Data, "data:image/(?.+?),(?.+)").Groups["data"].Value; - - var streamData = new MemoryStream(Convert.FromBase64String(base64Data)); - if (streamData.Length > 0) - { - string folder = typeof(T).Name; - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - folder = folder.Replace(@"\", "/", StringComparison.Ordinal); - } - - string folderName = supportedFileType switch - { - FileType.Image => Path.Combine("assets", "images", folder), - _ => Path.Combine("assets", "others", folder), - }; - string pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName); - Directory.CreateDirectory(pathToSave); - - string fileName = request.Name.Trim('"'); - fileName = RemoveSpecialCharacters(fileName); - fileName = fileName.ReplaceWhitespace("-"); - fileName += request.Extension.Trim(); - string fullPath = Path.Combine(pathToSave, fileName); - string dbPath = Path.Combine(folderName, fileName); - if (File.Exists(dbPath)) - { - dbPath = NextAvailableFilename(dbPath); - fullPath = NextAvailableFilename(fullPath); - } - - using var stream = new FileStream(fullPath, FileMode.Create); - await streamData.CopyToAsync(stream, cancellationToken); - var path = dbPath.Replace("\\", "/", StringComparison.Ordinal); - var imageUri = new Uri(originSettings.Value.OriginUrl!, path); - return imageUri; - } - else - { - return null!; - } - } - - public static string RemoveSpecialCharacters(string str) - { - return Regex.Replace(str, "[^a-zA-Z0-9_.]+", string.Empty, RegexOptions.Compiled); - } - - public void Remove(Uri? path) - { - var pathString = path!.ToString(); - if (File.Exists(pathString)) - { - File.Delete(pathString); - } - } - - private const string NumberPattern = "-{0}"; - - private static string NextAvailableFilename(string path) - { - if (!File.Exists(path)) - { - return path; - } - - if (Path.HasExtension(path)) - { - return GetNextFilename(path.Insert(path.LastIndexOf(Path.GetExtension(path), StringComparison.Ordinal), NumberPattern)); - } - - return GetNextFilename(path + NumberPattern); - } - - private static string GetNextFilename(string pattern) - { - string tmp = string.Format(pattern, 1); - - if (!File.Exists(tmp)) - { - return tmp; - } - - int min = 1, max = 2; - - while (File.Exists(string.Format(pattern, max))) - { - min = max; - max *= 2; - } - - while (max != min + 1) - { - int pivot = (max + min) / 2; - if (File.Exists(string.Format(pattern, pivot))) - { - min = pivot; - } - else - { - max = pivot; - } - } - - return string.Format(pattern, max); - } - } -} diff --git a/src/framework/Infrastructure/Storage/LocalStorageService.cs b/src/framework/Infrastructure/Storage/LocalStorageService.cs new file mode 100644 index 000000000..ab1c98025 --- /dev/null +++ b/src/framework/Infrastructure/Storage/LocalStorageService.cs @@ -0,0 +1,58 @@ +namespace FSH.Framework.Infrastructure.Storage; +using System.Text.RegularExpressions; +using FSH.Framework.Core.Storage; + +public class LocalStorageService : IStorageService +{ + private const string RootPath = "wwwroot"; + private const string UploadBasePath = "uploads"; + + public async Task UploadAsync(FileUploadRequest request, FileType fileType, CancellationToken cancellationToken = default) + where T : class + { + var rules = FileTypeMetadata.GetRules(fileType); + var extension = Path.GetExtension(request.FileName); + + if (string.IsNullOrWhiteSpace(extension) || + !rules.AllowedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) + { + throw new InvalidOperationException($"File type '{extension}' is not allowed. Allowed: {string.Join(", ", rules.AllowedExtensions)}"); + } + + if (request.Data.Count > rules.MaxSizeInMB * 1024 * 1024) + { + throw new InvalidOperationException($"File exceeds max size of {rules.MaxSizeInMB} MB."); + } + + var folder = Regex.Replace(typeof(T).Name.ToLowerInvariant(), @"[^a-z0-9]", "_"); + var safeFileName = $"{Guid.NewGuid():N}_{SanitizeFileName(request.FileName)}"; + var relativePath = Path.Combine(UploadBasePath, folder, safeFileName); + var fullPath = Path.Combine(RootPath, relativePath); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!); + + await File.WriteAllBytesAsync(fullPath, request.Data.ToArray(), cancellationToken); + + return relativePath.Replace("\\", "/"); // Normalize for URLs + } + + public Task RemoveAsync(string path, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(path)) return Task.CompletedTask; + + var fullPath = Path.Combine(RootPath, path); + + if (File.Exists(fullPath)) + { + File.Delete(fullPath); + } + + return Task.CompletedTask; + } + + private static string SanitizeFileName(string fileName) + { + return Regex.Replace(fileName, @"[^a-zA-Z0-9_\.-]", "_"); + } +} + diff --git a/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs b/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs new file mode 100644 index 000000000..0aa07f569 --- /dev/null +++ b/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs @@ -0,0 +1,14 @@ +using FSH.Framework.Core.Storage; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Infrastructure.Storage; +public static class StorageServiceRegistration +{ + public static IServiceCollection AddFileStorage(this IServiceCollection services, IConfiguration config) + { + // You can later use config["Storage:Provider"] to swap between implementations + services.AddScoped(); + return services; + } +} diff --git a/src/framework/Shared/Authorization/EndpointExtensions.cs b/src/framework/Shared/Authorization/EndpointExtensions.cs new file mode 100644 index 000000000..c3b2af3ca --- /dev/null +++ b/src/framework/Shared/Authorization/EndpointExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace FSH.Framework.Shared.Authorization; +public static class EndpointExtensions +{ + public static TBuilder RequirePermission( + this TBuilder endpointConventionBuilder, string requiredPermission, params string[] additionalRequiredPermissions) + where TBuilder : IEndpointConventionBuilder + { + return endpointConventionBuilder.WithMetadata(new RequiredPermissionAttribute(requiredPermission, additionalRequiredPermissions)); + } +} diff --git a/src/framework/Shared/Authorization/RequiredPermissionAttribute.cs b/src/framework/Shared/Authorization/RequiredPermissionAttribute.cs new file mode 100644 index 000000000..1730f9959 --- /dev/null +++ b/src/framework/Shared/Authorization/RequiredPermissionAttribute.cs @@ -0,0 +1,14 @@ +namespace FSH.Framework.Shared.Authorization; +public interface IRequiredPermissionMetadata +{ + HashSet RequiredPermissions { get; } +} + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public sealed class RequiredPermissionAttribute(string? requiredPermission, params string[]? additionalRequiredPermissions) + : Attribute, IRequiredPermissionMetadata +{ + public HashSet RequiredPermissions { get; } = [requiredPermission!, .. additionalRequiredPermissions]; + public string? RequiredPermission { get; } + public string[]? AdditionalRequiredPermissions { get; } +} diff --git a/src/framework/Shared/Shared.csproj b/src/framework/Shared/Shared.csproj new file mode 100644 index 000000000..10e90edc9 --- /dev/null +++ b/src/framework/Shared/Shared.csproj @@ -0,0 +1,14 @@ + + + FSH.Framework.Shared + FSH.Framework.Shared + + + net9.0 + enable + enable + + + + + From ae9d4f7202ff5bfeacc1b705e7fd8e313d820ea3 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 8 Apr 2025 16:10:19 +0530 Subject: [PATCH 04/54] identity changes --- src/Directory.Packages.props | 2 +- .../Abstractions/IUserService.cs | 9 +-- .../Identity/Identity.Core/Dtos/TokenDto.cs | 2 + .../Dtos/TokenGenerationRequest.cs | 2 + .../Identity.Core/Dtos/TokenRefreshRequest.cs | 2 + .../Identity.Core/Tokens/ITokenService.cs | 8 +-- .../Identity.Endpoints.csproj | 4 ++ .../Tokens/Generate/TokenGenerationCommand.cs | 14 ----- .../Generate}/TokenGenerationEndpoint.cs | 13 ++--- .../TokenGenerationRequestValidator.cs | 18 ++++++ .../Tokens/Refresh}/RefreshTokenEndpoint.cs | 13 ++--- ...and.cs => TokenRefreshRequestValidator.cs} | 7 +-- .../PermissionAuthorizationRequirement.cs | 2 +- ...quiredPermissionAuthorizationExtensions.cs | 32 +++++++++++ .../RequiredPermissionAuthorizationHandler.cs | 6 +- .../Identity.Infrastructure.csproj | 8 ++- .../Auth/Policy/EndpointExtensions.cs | 12 ---- .../Policy/RequiredPermissionAttribute.cs | 14 ----- .../Shared/Authorization/CustomClaims.cs | 10 ++++ .../Extensions/ClaimsPrincipalExtensions.cs | 55 +++++++++++++++++++ .../Extensions/HttpContextExtensions.cs | 20 +++++++ 21 files changed, 178 insertions(+), 75 deletions(-) create mode 100644 src/framework/Identity/Identity.Core/Dtos/TokenDto.cs create mode 100644 src/framework/Identity/Identity.Core/Dtos/TokenGenerationRequest.cs create mode 100644 src/framework/Identity/Identity.Core/Dtos/TokenRefreshRequest.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs rename src/framework/{Infrastructure/Identity/Tokens/Endpoints => Identity/Identity.Endpoints/v1/Tokens/Generate}/TokenGenerationEndpoint.cs (64%) create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs rename src/framework/{Infrastructure/Identity/Tokens/Endpoints => Identity/Identity.Endpoints/v1/Tokens/Refresh}/RefreshTokenEndpoint.cs (63%) rename src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/{RefreshTokenCommand.cs => TokenRefreshRequestValidator.cs} (57%) rename src/framework/{Infrastructure/Auth/Policy => Identity/Identity.Infrastructure/Authorization}/PermissionAuthorizationRequirement.cs (66%) create mode 100644 src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs delete mode 100644 src/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs delete mode 100644 src/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs create mode 100644 src/framework/Shared/Authorization/CustomClaims.cs create mode 100644 src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs create mode 100644 src/framework/Shared/Extensions/HttpContextExtensions.cs diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index c1d0d5b2c..a1d8d0705 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -23,7 +23,7 @@ - + diff --git a/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs b/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs index e22ef248c..df9a4629d 100644 --- a/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs +++ b/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs @@ -1,15 +1,8 @@ using System.Security.Claims; using FSH.Framework.Core.Identity.Users.Dtos; -using FSH.Framework.Core.Identity.Users.Features.AssignUserRole; -using FSH.Framework.Core.Identity.Users.Features.ChangePassword; -using FSH.Framework.Core.Identity.Users.Features.ForgotPassword; -using FSH.Framework.Core.Identity.Users.Features.RegisterUser; -using FSH.Framework.Core.Identity.Users.Features.ResetPassword; -using FSH.Framework.Core.Identity.Users.Features.ToggleUserStatus; -using FSH.Framework.Core.Identity.Users.Features.UpdateUser; using FSH.Framework.Identity.Core.Dtos; -namespace FSH.Framework.Core.Identity.Users.Abstractions; +namespace FSH.Framework.Identity.Core.Abstractions; public interface IUserService { Task ExistsWithNameAsync(string name); diff --git a/src/framework/Identity/Identity.Core/Dtos/TokenDto.cs b/src/framework/Identity/Identity.Core/Dtos/TokenDto.cs new file mode 100644 index 000000000..6fec92a16 --- /dev/null +++ b/src/framework/Identity/Identity.Core/Dtos/TokenDto.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Identity.Core.Dtos; +public record TokenDto(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); diff --git a/src/framework/Identity/Identity.Core/Dtos/TokenGenerationRequest.cs b/src/framework/Identity/Identity.Core/Dtos/TokenGenerationRequest.cs new file mode 100644 index 000000000..c96f9a6c7 --- /dev/null +++ b/src/framework/Identity/Identity.Core/Dtos/TokenGenerationRequest.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Identity.Core.Dtos; +public record TokenGenerationRequest(string Email, string Password); diff --git a/src/framework/Identity/Identity.Core/Dtos/TokenRefreshRequest.cs b/src/framework/Identity/Identity.Core/Dtos/TokenRefreshRequest.cs new file mode 100644 index 000000000..41c981858 --- /dev/null +++ b/src/framework/Identity/Identity.Core/Dtos/TokenRefreshRequest.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Identity.Core.Dtos; +public record TokenRefreshRequest(string Token, string RefreshToken); diff --git a/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs index 72359a31e..7c1884ade 100644 --- a/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs +++ b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs @@ -1,11 +1,9 @@ -using FSH.Framework.Core.Identity.Tokens.Features.Generate; -using FSH.Framework.Core.Identity.Tokens.Features.Refresh; -using FSH.Framework.Core.Identity.Tokens.Models; +using FSH.Framework.Identity.Core.Dtos; namespace FSH.Framework.Identity.Core.Tokens; public interface ITokenService { - Task GenerateTokenAsync(TokenGenerationCommand request, string ipAddress, CancellationToken cancellationToken); - Task RefreshTokenAsync(RefreshTokenCommand request, string ipAddress, CancellationToken cancellationToken); + Task GenerateTokenAsync(TokenGenerationRequest request, string ipAddress, CancellationToken cancellationToken); + Task RefreshTokenAsync(TokenRefreshRequest request, string ipAddress, CancellationToken cancellationToken); } diff --git a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj index 334864d8b..30876e2b9 100644 --- a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj +++ b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj @@ -12,8 +12,12 @@ + + + + diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs deleted file mode 100644 index 151d67339..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs +++ /dev/null @@ -1,14 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; -public record TokenGenerationCommand(string Email, string Password); - -public class GenerateTokenValidator : AbstractValidator -{ - public GenerateTokenValidator() - { - RuleFor(p => p.Email).Cascade(CascadeMode.Stop).NotEmpty().EmailAddress(); - - RuleFor(p => p.Password).Cascade(CascadeMode.Stop).NotEmpty(); - } -} diff --git a/src/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs similarity index 64% rename from src/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs rename to src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs index e0bbc4796..3b81fdd0b 100644 --- a/src/framework/Infrastructure/Identity/Tokens/Endpoints/TokenGenerationEndpoint.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs @@ -1,18 +1,17 @@ -using FSH.Framework.Core.Identity.Tokens; -using FSH.Framework.Core.Identity.Tokens.Features.Generate; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Core.Dtos; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Infrastructure.Identity.Tokens.Endpoints; +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; public static class TokenGenerationEndpoint { internal static RouteHandlerBuilder MapTokenGenerationEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/", (TokenGenerationCommand request, - [FromHeader(Name = TenantConstants.Identifier)] string tenant, + return endpoints.MapPost("/", (TokenGenerationRequest request, + string tenant, ITokenService service, HttpContext context, CancellationToken cancellationToken) => diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs new file mode 100644 index 000000000..a22b0d493 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using FSH.Framework.Identity.Core.Dtos; + +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; +public class TokenGenerationRequestValidator : AbstractValidator +{ + public TokenGenerationRequestValidator() + { + RuleFor(p => p.Email) + .Cascade(CascadeMode.Stop) + .NotEmpty() + .EmailAddress(); + + RuleFor(p => p.Password) + .Cascade(CascadeMode.Stop) + .NotEmpty(); + } +} diff --git a/src/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs similarity index 63% rename from src/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs rename to src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs index a8f27128b..01c2316d4 100644 --- a/src/framework/Infrastructure/Identity/Tokens/Endpoints/RefreshTokenEndpoint.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs @@ -1,18 +1,17 @@ -using FSH.Framework.Core.Identity.Tokens; -using FSH.Framework.Core.Identity.Tokens.Features.Refresh; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Core.Dtos; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Infrastructure.Identity.Tokens.Endpoints; +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Refresh; public static class RefreshTokenEndpoint { internal static RouteHandlerBuilder MapRefreshTokenEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/refresh", (RefreshTokenCommand request, - [FromHeader(Name = TenantConstants.Identifier)] string tenant, + return endpoints.MapPost("/refresh", (TokenRefreshRequest request, + string tenant, ITokenService service, HttpContext context, CancellationToken cancellationToken) => diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs similarity index 57% rename from src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenCommand.cs rename to src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs index 8e55cd6a7..79410bb9e 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenCommand.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs @@ -1,11 +1,10 @@ using FluentValidation; +using FSH.Framework.Identity.Core.Dtos; namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Refresh; -public record RefreshTokenCommand(string Token, string RefreshToken); - -public class RefreshTokenValidator : AbstractValidator +public class TokenRefreshRequestValidator : AbstractValidator { - public RefreshTokenValidator() + public TokenRefreshRequestValidator() { RuleFor(p => p.Token).Cascade(CascadeMode.Stop).NotEmpty(); diff --git a/src/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs b/src/framework/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs similarity index 66% rename from src/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs rename to src/framework/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs index 128692181..8a6e8d6fb 100644 --- a/src/framework/Infrastructure/Auth/Policy/PermissionAuthorizationRequirement.cs +++ b/src/framework/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs @@ -1,4 +1,4 @@ using Microsoft.AspNetCore.Authorization; -namespace FSH.Framework.Infrastructure.Auth.Policy; +namespace FSH.Framework.Identity.Infrastructure.Authorization; public class PermissionAuthorizationRequirement : IAuthorizationRequirement; diff --git a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs new file mode 100644 index 000000000..ec51a0b1c --- /dev/null +++ b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace FSH.Framework.Identity.Infrastructure.Authorization; +public static class RequiredPermissionDefaults +{ + public const string PolicyName = "RequiredPermission"; +} + +public static class RequiredPermissionAuthorizationExtensions +{ + public static AuthorizationPolicyBuilder RequireRequiredPermissions(this AuthorizationPolicyBuilder builder) + { + return builder.AddRequirements(new PermissionAuthorizationRequirement()); + } + + public static AuthorizationBuilder AddRequiredPermissionPolicy(this AuthorizationBuilder builder) + { + builder.AddPolicy(RequiredPermissionDefaults.PolicyName, policy => + { + policy.RequireAuthenticatedUser(); + policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme); + policy.RequireRequiredPermissions(); + }); + + builder.Services.TryAddEnumerable(ServiceDescriptor.Scoped()); + + return builder; + } +} diff --git a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs index 162bbcb32..92c3b90ff 100644 --- a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs +++ b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs @@ -1,4 +1,8 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; +using FSH.Framework.Identity.Core.Abstractions; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Shared.Extensions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; namespace FSH.Framework.Identity.Infrastructure.Authorization; public sealed class RequiredPermissionAuthorizationHandler(IUserService userService) : AuthorizationHandler diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index 48c7c4f40..f4e2960b9 100644 --- a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -9,7 +9,13 @@ enable + - + + + + + + diff --git a/src/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs b/src/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs deleted file mode 100644 index 7cd6ea7e1..000000000 --- a/src/framework/Infrastructure/Auth/Policy/EndpointExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.AspNetCore.Builder; - -namespace FSH.Framework.Infrastructure.Auth.Policy; -public static class EndpointExtensions -{ - public static TBuilder RequirePermission( - this TBuilder endpointConventionBuilder, string requiredPermission, params string[] additionalRequiredPermissions) - where TBuilder : IEndpointConventionBuilder - { - return endpointConventionBuilder.WithMetadata(new RequiredPermissionAttribute(requiredPermission, additionalRequiredPermissions)); - } -} diff --git a/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs b/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs deleted file mode 100644 index cf7ea3d91..000000000 --- a/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace FSH.Framework.Infrastructure.Auth.Policy; -public interface IRequiredPermissionMetadata -{ - HashSet RequiredPermissions { get; } -} - -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] -public sealed class RequiredPermissionAttribute(string? requiredPermission, params string[]? additionalRequiredPermissions) - : Attribute, IRequiredPermissionMetadata -{ - public HashSet RequiredPermissions { get; } = [requiredPermission!, .. additionalRequiredPermissions]; - public string? RequiredPermission { get; } - public string[]? AdditionalRequiredPermissions { get; } -} diff --git a/src/framework/Shared/Authorization/CustomClaims.cs b/src/framework/Shared/Authorization/CustomClaims.cs new file mode 100644 index 000000000..4f1566ca1 --- /dev/null +++ b/src/framework/Shared/Authorization/CustomClaims.cs @@ -0,0 +1,10 @@ +namespace FSH.Framework.Shared.Authorization; +public static class CustomClaims +{ + public const string Tenant = "tenant"; + public const string Fullname = "fullName"; + public const string Permission = "permission"; + public const string ImageUrl = "image_url"; + public const string IpAddress = "ipAddress"; + public const string Expiration = "exp"; +} diff --git a/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs b/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs new file mode 100644 index 000000000..0d351dfcd --- /dev/null +++ b/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs @@ -0,0 +1,55 @@ +using System.Security.Claims; +using FSH.Framework.Shared.Authorization; + +namespace FSH.Framework.Shared.Extensions; + +public static class ClaimsPrincipalExtensions +{ + // Retrieves the email claim + public static string? GetEmail(this ClaimsPrincipal principal) => + principal?.FindFirstValue(ClaimTypes.Email); + + // Retrieves the tenant claim + public static string? GetTenant(this ClaimsPrincipal principal) => + principal?.FindFirstValue(CustomClaims.Tenant); + + // Retrieves the user's full name + public static string? GetFullName(this ClaimsPrincipal principal) => + principal?.FindFirstValue(CustomClaims.Fullname); + + // Retrieves the user's first name + public static string? GetFirstName(this ClaimsPrincipal principal) => + principal?.FindFirstValue(ClaimTypes.Name); + + // Retrieves the user's surname + public static string? GetSurname(this ClaimsPrincipal principal) => + principal?.FindFirstValue(ClaimTypes.Surname); + + // Retrieves the user's phone number + public static string? GetPhoneNumber(this ClaimsPrincipal principal) => + principal?.FindFirstValue(ClaimTypes.MobilePhone); + + // Retrieves the user's ID + public static string? GetUserId(this ClaimsPrincipal principal) => + principal?.FindFirstValue(ClaimTypes.NameIdentifier); + + // Retrieves the user's image URL as Uri + public static Uri? GetImageUrl(this ClaimsPrincipal principal) + { + var imageUrl = principal?.FindFirstValue(CustomClaims.ImageUrl); + return Uri.TryCreate(imageUrl, UriKind.Absolute, out var uri) ? uri : null; + } + + // Retrieves the user's token expiration date + public static DateTimeOffset GetExpiration(this ClaimsPrincipal principal) + { + var expiration = principal?.FindFirstValue(CustomClaims.Expiration); + return expiration != null + ? DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(expiration)) + : throw new InvalidOperationException("Expiration claim not found."); + } + + // Helper method to extract claim value + private static string? FindFirstValue(this ClaimsPrincipal principal, string claimType) => + principal?.FindFirst(claimType)?.Value; +} diff --git a/src/framework/Shared/Extensions/HttpContextExtensions.cs b/src/framework/Shared/Extensions/HttpContextExtensions.cs new file mode 100644 index 000000000..50d9538fd --- /dev/null +++ b/src/framework/Shared/Extensions/HttpContextExtensions.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Http; + +namespace FSH.Framework.Shared.Extensions; + +public static class HttpContextExtensions +{ + public static string GetIpAddress(this HttpContext context) + { + string ip = "N/A"; + if (context.Request.Headers.TryGetValue("X-Forwarded-For", out var ipList)) + { + ip = ipList.FirstOrDefault() ?? "N/A"; + } + else if (context.Connection.RemoteIpAddress != null) + { + ip = context.Connection.RemoteIpAddress.MapToIPv4().ToString(); + } + return ip; + } +} From a8370f9a4e9d288296eb2f9d226c91f41eda6518 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 8 Apr 2025 16:35:58 +0530 Subject: [PATCH 05/54] stash --- src/framework/Identity/Identity.Core/Tokens/ITokenService.cs | 4 +--- .../Identity/Identity.Core/{Dtos => Tokens}/TokenDto.cs | 2 +- .../Identity.Core/{Dtos => Tokens}/TokenGenerationRequest.cs | 2 +- .../Identity.Core/{Dtos => Tokens}/TokenRefreshRequest.cs | 2 +- .../{Abstractions => Users}/ICurrentUserInitializer.cs | 2 +- .../Identity.Core/{Abstractions => Users}/IUserService.cs | 2 +- .../v1/Tokens/Generate/TokenGenerationEndpoint.cs | 3 +-- .../v1/Tokens/Generate/TokenGenerationRequestValidator.cs | 2 +- .../v1/Tokens/Refresh/RefreshTokenEndpoint.cs | 3 +-- .../v1/Tokens/Refresh/TokenRefreshRequestValidator.cs | 2 +- .../Authorization/RequiredPermissionAuthorizationHandler.cs | 2 +- 11 files changed, 11 insertions(+), 15 deletions(-) rename src/framework/Identity/Identity.Core/{Dtos => Tokens}/TokenDto.cs (65%) rename src/framework/Identity/Identity.Core/{Dtos => Tokens}/TokenGenerationRequest.cs (58%) rename src/framework/Identity/Identity.Core/{Dtos => Tokens}/TokenRefreshRequest.cs (58%) rename src/framework/Identity/Identity.Core/{Abstractions => Users}/ICurrentUserInitializer.cs (76%) rename src/framework/Identity/Identity.Core/{Abstractions => Users}/IUserService.cs (97%) diff --git a/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs index 7c1884ade..b6acb2a39 100644 --- a/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs +++ b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs @@ -1,6 +1,4 @@ -using FSH.Framework.Identity.Core.Dtos; - -namespace FSH.Framework.Identity.Core.Tokens; +namespace FSH.Framework.Identity.Core.Tokens; public interface ITokenService { Task GenerateTokenAsync(TokenGenerationRequest request, string ipAddress, CancellationToken cancellationToken); diff --git a/src/framework/Identity/Identity.Core/Dtos/TokenDto.cs b/src/framework/Identity/Identity.Core/Tokens/TokenDto.cs similarity index 65% rename from src/framework/Identity/Identity.Core/Dtos/TokenDto.cs rename to src/framework/Identity/Identity.Core/Tokens/TokenDto.cs index 6fec92a16..cc90e9a8f 100644 --- a/src/framework/Identity/Identity.Core/Dtos/TokenDto.cs +++ b/src/framework/Identity/Identity.Core/Tokens/TokenDto.cs @@ -1,2 +1,2 @@ -namespace FSH.Framework.Identity.Core.Dtos; +namespace FSH.Framework.Identity.Core.Tokens; public record TokenDto(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); diff --git a/src/framework/Identity/Identity.Core/Dtos/TokenGenerationRequest.cs b/src/framework/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs similarity index 58% rename from src/framework/Identity/Identity.Core/Dtos/TokenGenerationRequest.cs rename to src/framework/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs index c96f9a6c7..afcbfee2f 100644 --- a/src/framework/Identity/Identity.Core/Dtos/TokenGenerationRequest.cs +++ b/src/framework/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs @@ -1,2 +1,2 @@ -namespace FSH.Framework.Identity.Core.Dtos; +namespace FSH.Framework.Identity.Core.Tokens; public record TokenGenerationRequest(string Email, string Password); diff --git a/src/framework/Identity/Identity.Core/Dtos/TokenRefreshRequest.cs b/src/framework/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs similarity index 58% rename from src/framework/Identity/Identity.Core/Dtos/TokenRefreshRequest.cs rename to src/framework/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs index 41c981858..488801058 100644 --- a/src/framework/Identity/Identity.Core/Dtos/TokenRefreshRequest.cs +++ b/src/framework/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs @@ -1,2 +1,2 @@ -namespace FSH.Framework.Identity.Core.Dtos; +namespace FSH.Framework.Identity.Core.Tokens; public record TokenRefreshRequest(string Token, string RefreshToken); diff --git a/src/framework/Identity/Identity.Core/Abstractions/ICurrentUserInitializer.cs b/src/framework/Identity/Identity.Core/Users/ICurrentUserInitializer.cs similarity index 76% rename from src/framework/Identity/Identity.Core/Abstractions/ICurrentUserInitializer.cs rename to src/framework/Identity/Identity.Core/Users/ICurrentUserInitializer.cs index 161fdde45..1824b7086 100644 --- a/src/framework/Identity/Identity.Core/Abstractions/ICurrentUserInitializer.cs +++ b/src/framework/Identity/Identity.Core/Users/ICurrentUserInitializer.cs @@ -1,6 +1,6 @@ using System.Security.Claims; -namespace FSH.Framework.Identity.Core.Abstractions; +namespace FSH.Framework.Identity.Core.Users; public interface ICurrentUserInitializer { void SetCurrentUser(ClaimsPrincipal user); diff --git a/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs b/src/framework/Identity/Identity.Core/Users/IUserService.cs similarity index 97% rename from src/framework/Identity/Identity.Core/Abstractions/IUserService.cs rename to src/framework/Identity/Identity.Core/Users/IUserService.cs index df9a4629d..e0083178a 100644 --- a/src/framework/Identity/Identity.Core/Abstractions/IUserService.cs +++ b/src/framework/Identity/Identity.Core/Users/IUserService.cs @@ -2,7 +2,7 @@ using FSH.Framework.Core.Identity.Users.Dtos; using FSH.Framework.Identity.Core.Dtos; -namespace FSH.Framework.Identity.Core.Abstractions; +namespace FSH.Framework.Identity.Core.Users; public interface IUserService { Task ExistsWithNameAsync(string name); diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs index 3b81fdd0b..cb6b5cba9 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs @@ -1,5 +1,4 @@ -using FSH.Framework.Identity.Core.Dtos; -using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs index a22b0d493..c42322215 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs @@ -1,5 +1,5 @@ using FluentValidation; -using FSH.Framework.Identity.Core.Dtos; +using FSH.Framework.Identity.Core.Tokens; namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; public class TokenGenerationRequestValidator : AbstractValidator diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs index 01c2316d4..47e7b2545 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs @@ -1,5 +1,4 @@ -using FSH.Framework.Identity.Core.Dtos; -using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs index 79410bb9e..c1f3d7939 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs @@ -1,5 +1,5 @@ using FluentValidation; -using FSH.Framework.Identity.Core.Dtos; +using FSH.Framework.Identity.Core.Tokens; namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Refresh; public class TokenRefreshRequestValidator : AbstractValidator diff --git a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs index 92c3b90ff..f43aeb098 100644 --- a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs +++ b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Identity.Core.Abstractions; +using FSH.Framework.Identity.Core.Users; using FSH.Framework.Shared.Authorization; using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Authorization; From c551fcee4aac73da0fdecb3fbb67bfa482c296f2 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 8 Apr 2025 16:50:05 +0530 Subject: [PATCH 06/54] cleanup --- .../Behaviors/ValidationBehavior.cs | 31 +++++-- .../Extensions/ServiceCollectionExtensions.cs | 10 -- .../Exceptions/CustomException.cs | 2 +- .../Exceptions/ForbiddenException.cs | 2 +- .../Exceptions/NotFoundException.cs | 2 +- .../Exceptions/UnauthorizedException.cs | 2 +- .../Identity/Tokens/Models/TokenResponse.cs | 2 - .../SpecificationBuilderExtensions.cs | 92 +++++++++++-------- .../Identity.Infrastructure}/JwtOptions.cs | 2 +- .../Behaviours/ValidationBehavior.cs | 23 ----- 10 files changed, 81 insertions(+), 87 deletions(-) delete mode 100644 src/framework/Application/Extensions/ServiceCollectionExtensions.cs rename src/framework/{Application => Core}/Exceptions/CustomException.cs (96%) rename src/framework/{Application => Core}/Exceptions/ForbiddenException.cs (92%) rename src/framework/{Application => Core}/Exceptions/NotFoundException.cs (90%) rename src/framework/{Application => Core}/Exceptions/UnauthorizedException.cs (92%) delete mode 100644 src/framework/Core/Identity/Tokens/Models/TokenResponse.cs rename src/framework/{Core/Auth/Jwt => Identity/Identity.Infrastructure}/JwtOptions.cs (91%) delete mode 100644 src/framework/Infrastructure/Behaviours/ValidationBehavior.cs diff --git a/src/framework/Application/Behaviors/ValidationBehavior.cs b/src/framework/Application/Behaviors/ValidationBehavior.cs index f3ae4fa8f..80cc3a68e 100644 --- a/src/framework/Application/Behaviors/ValidationBehavior.cs +++ b/src/framework/Application/Behaviors/ValidationBehavior.cs @@ -1,23 +1,40 @@ using FluentValidation; using MediatR; -namespace FSH.Framework.Application.Behaviours; -public class ValidationBehavior(IEnumerable> validators) : IPipelineBehavior +namespace FSH.Framework.Application.Behaviors; + +public class ValidationBehavior : IPipelineBehavior where TRequest : IRequest { - private readonly IEnumerable> _validators = validators; + private readonly IEnumerable> _validators; + + public ValidationBehavior(IEnumerable> validators) + { + _validators = validators; + } - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + public async Task Handle( + TRequest request, + RequestHandlerDelegate next, + CancellationToken cancellationToken) { if (_validators.Any()) { var context = new ValidationContext(request); - var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken))); - var failures = validationResults.SelectMany(r => r.Errors).Where(f => f != null).ToList(); + + var validationResults = await Task.WhenAll( + _validators.Select(v => v.ValidateAsync(context, cancellationToken)) + ); + + var failures = validationResults + .SelectMany(result => result.Errors) + .Where(error => error is not null) + .ToList(); if (failures.Count > 0) throw new ValidationException(failures); } - return await next(); + + return await next(cancellationToken); } } diff --git a/src/framework/Application/Extensions/ServiceCollectionExtensions.cs b/src/framework/Application/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 1aff1b794..000000000 --- a/src/framework/Application/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace FSH.Framework.Application.Extensions; -internal class ServiceCollectionExtensions -{ -} diff --git a/src/framework/Application/Exceptions/CustomException.cs b/src/framework/Core/Exceptions/CustomException.cs similarity index 96% rename from src/framework/Application/Exceptions/CustomException.cs rename to src/framework/Core/Exceptions/CustomException.cs index 4143639ff..cf3688fb4 100644 --- a/src/framework/Application/Exceptions/CustomException.cs +++ b/src/framework/Core/Exceptions/CustomException.cs @@ -1,6 +1,6 @@ using System.Net; -namespace FSH.Framework.Application.Exceptions; +namespace FSH.Framework.Core.Exceptions; /// /// FullStackHero exception used for consistent error handling across the stack. diff --git a/src/framework/Application/Exceptions/ForbiddenException.cs b/src/framework/Core/Exceptions/ForbiddenException.cs similarity index 92% rename from src/framework/Application/Exceptions/ForbiddenException.cs rename to src/framework/Core/Exceptions/ForbiddenException.cs index d35d4b187..1041b72a3 100644 --- a/src/framework/Application/Exceptions/ForbiddenException.cs +++ b/src/framework/Core/Exceptions/ForbiddenException.cs @@ -1,6 +1,6 @@ using System.Net; -namespace FSH.Framework.Application.Exceptions; +namespace FSH.Framework.Core.Exceptions; /// /// Exception representing a 403 Forbidden error. diff --git a/src/framework/Application/Exceptions/NotFoundException.cs b/src/framework/Core/Exceptions/NotFoundException.cs similarity index 90% rename from src/framework/Application/Exceptions/NotFoundException.cs rename to src/framework/Core/Exceptions/NotFoundException.cs index 5edcad79c..0d12f8dbf 100644 --- a/src/framework/Application/Exceptions/NotFoundException.cs +++ b/src/framework/Core/Exceptions/NotFoundException.cs @@ -1,6 +1,6 @@ using System.Net; -namespace FSH.Framework.Application.Exceptions; +namespace FSH.Framework.Core.Exceptions; /// /// Exception representing a 404 Not Found error. diff --git a/src/framework/Application/Exceptions/UnauthorizedException.cs b/src/framework/Core/Exceptions/UnauthorizedException.cs similarity index 92% rename from src/framework/Application/Exceptions/UnauthorizedException.cs rename to src/framework/Core/Exceptions/UnauthorizedException.cs index 50264ed12..35802df53 100644 --- a/src/framework/Application/Exceptions/UnauthorizedException.cs +++ b/src/framework/Core/Exceptions/UnauthorizedException.cs @@ -1,6 +1,6 @@ using System.Net; -namespace FSH.Framework.Application.Exceptions; +namespace FSH.Framework.Core.Exceptions; /// /// Exception representing a 401 Unauthorized error (authentication failure). diff --git a/src/framework/Core/Identity/Tokens/Models/TokenResponse.cs b/src/framework/Core/Identity/Tokens/Models/TokenResponse.cs deleted file mode 100644 index fc56f00d8..000000000 --- a/src/framework/Core/Identity/Tokens/Models/TokenResponse.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Core.Identity.Tokens.Models; -public record TokenResponse(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); diff --git a/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs b/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs index 81b352056..7be1545d3 100644 --- a/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs +++ b/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs @@ -16,28 +16,30 @@ public static ISpecificationBuilder SearchBy(this ISpecificationBuilder .AdvancedSearch(filter.AdvancedSearch) .AdvancedFilter(filter.AdvancedFilter); - public static ISpecificationBuilder PaginateBy(this ISpecificationBuilder query, PaginationFilter filter) + public static ISpecificationBuilder PaginateBy( + this ISpecificationBuilder query, + PaginationFilter filter) { - if (filter.PageNumber <= 0) - { - filter.PageNumber = 1; - } + var pageNumber = filter.PageNumber <= 0 ? 1 : filter.PageNumber; + var pageSize = filter.PageSize <= 0 ? 10 : filter.PageSize; - if (filter.PageSize <= 0) + if (pageNumber > 1) { - filter.PageSize = 10; + query = query.Skip((pageNumber - 1) * pageSize); } - if (filter.PageNumber > 1) + query = query.Take(pageSize); + + if (filter.OrderBy is { Count: > 0 }) { - query = query.Skip((filter.PageNumber - 1) * filter.PageSize); + query = query.OrderBy(filter.OrderBy); } - return query - .Take(filter.PageSize) - .OrderBy(filter.OrderBy); + return query; } + + public static IOrderedSpecificationBuilder SearchByKeyword( this ISpecificationBuilder specificationBuilder, string? keyword) => @@ -84,19 +86,19 @@ private static void AddSearchPropertyByKeyword( Expression propertyExpr, ParameterExpression paramExpr, string keyword, - string operatorSearch = FilterOperator.CONTAINS) + FilterOperator operatorSearch = FilterOperator.Contains) { if (propertyExpr is not MemberExpression memberExpr || memberExpr.Member is not PropertyInfo property) { throw new ArgumentException("propertyExpr must be a property expression.", nameof(propertyExpr)); } - string searchTerm = operatorSearch switch + var searchTerm = operatorSearch switch { - FilterOperator.STARTSWITH => $"{keyword.ToLower()}%", - FilterOperator.ENDSWITH => $"%{keyword.ToLower()}", - FilterOperator.CONTAINS => $"%{keyword.ToLower()}%", - _ => throw new ArgumentException("operatorSearch is not valid.", nameof(operatorSearch)) + FilterOperator.StartsWith => $"{keyword.ToLower()}%", + FilterOperator.EndsWith => $"%{keyword.ToLower()}", + FilterOperator.Contains => $"%{keyword.ToLower()}%", + _ => throw new CustomException($"Unsupported filter operator: {operatorSearch}") }; // Generate lambda [ x => x.Property ] for string properties @@ -188,39 +190,44 @@ private static Expression CreateFilterExpression( private static Expression CreateFilterExpression( Expression memberExpression, Expression constantExpression, - string filterOperator) + FilterOperator filterOperator) { if (memberExpression.Type == typeof(string)) { - constantExpression = Expression.Call(constantExpression, "ToLower", null); - memberExpression = Expression.Call(memberExpression, "ToLower", null); + constantExpression = Expression.Call(constantExpression, nameof(string.ToLower), null); + memberExpression = Expression.Call(memberExpression, nameof(string.ToLower), null); } return filterOperator switch { - FilterOperator.EQ => Expression.Equal(memberExpression, constantExpression), - FilterOperator.NEQ => Expression.NotEqual(memberExpression, constantExpression), - FilterOperator.LT => Expression.LessThan(memberExpression, constantExpression), - FilterOperator.LTE => Expression.LessThanOrEqual(memberExpression, constantExpression), - FilterOperator.GT => Expression.GreaterThan(memberExpression, constantExpression), - FilterOperator.GTE => Expression.GreaterThanOrEqual(memberExpression, constantExpression), - FilterOperator.CONTAINS => Expression.Call(memberExpression, "Contains", null, constantExpression), - FilterOperator.STARTSWITH => Expression.Call(memberExpression, "StartsWith", null, constantExpression), - FilterOperator.ENDSWITH => Expression.Call(memberExpression, "EndsWith", null, constantExpression), - _ => throw new CustomException("Filter Operator is not valid."), + FilterOperator.Eq => Expression.Equal(memberExpression, constantExpression), + FilterOperator.Neq => Expression.NotEqual(memberExpression, constantExpression), + FilterOperator.Lt => Expression.LessThan(memberExpression, constantExpression), + FilterOperator.Lte => Expression.LessThanOrEqual(memberExpression, constantExpression), + FilterOperator.Gt => Expression.GreaterThan(memberExpression, constantExpression), + FilterOperator.Gte => Expression.GreaterThanOrEqual(memberExpression, constantExpression), + FilterOperator.Contains => Expression.Call(memberExpression, nameof(string.Contains), null, constantExpression), + FilterOperator.StartsWith => Expression.Call(memberExpression, nameof(string.StartsWith), null, constantExpression), + FilterOperator.EndsWith => Expression.Call(memberExpression, nameof(string.EndsWith), null, constantExpression), + _ => throw new CustomException("Filter operator is not valid.") }; } + private static Expression CombineFilter( - string filterOperator, - Expression bExpresionBase, - Expression bExpresion) => filterOperator switch + FilterLogic logic, + Expression left, + Expression right) + { + return logic switch { - FilterLogic.AND => Expression.And(bExpresionBase, bExpresion), - FilterLogic.OR => Expression.Or(bExpresionBase, bExpresion), - FilterLogic.XOR => Expression.ExclusiveOr(bExpresionBase, bExpresion), - _ => throw new ArgumentException("FilterLogic is not valid."), + FilterLogic.And => Expression.And(left, right), + FilterLogic.Or => Expression.Or(left, right), + FilterLogic.Xor => Expression.ExclusiveOr(left, right), + _ => throw new ArgumentOutOfRangeException(nameof(logic), "Invalid filter logic.") }; + } + private static MemberExpression GetPropertyExpression( string propertyName, @@ -298,8 +305,13 @@ private static ConstantExpression GeValuetExpression( private static Filter GetValidFilter(Filter filter) { - if (string.IsNullOrEmpty(filter.Field)) throw new CustomException("The field attribute is required when declaring a filter"); - if (string.IsNullOrEmpty(filter.Operator)) throw new CustomException("The Operator attribute is required when declaring a filter"); + if (string.IsNullOrWhiteSpace(filter.Field)) + throw new CustomException("The 'Field' property is required when declaring a filter."); + + // Optional: check if Operator is defined in the enum (defensive) + if (!Enum.IsDefined(typeof(FilterOperator), filter.Operator!)) + throw new CustomException($"Invalid filter operator: {filter.Operator}"); + return filter; } diff --git a/src/framework/Core/Auth/Jwt/JwtOptions.cs b/src/framework/Identity/Identity.Infrastructure/JwtOptions.cs similarity index 91% rename from src/framework/Core/Auth/Jwt/JwtOptions.cs rename to src/framework/Identity/Identity.Infrastructure/JwtOptions.cs index 5d99d6702..8f5ff30ec 100644 --- a/src/framework/Core/Auth/Jwt/JwtOptions.cs +++ b/src/framework/Identity/Identity.Infrastructure/JwtOptions.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace FSH.Framework.Core.Auth.Jwt; +namespace FSH.Framework.Identity.Infrastructure; public class JwtOptions : IValidatableObject { public string Key { get; set; } = string.Empty; diff --git a/src/framework/Infrastructure/Behaviours/ValidationBehavior.cs b/src/framework/Infrastructure/Behaviours/ValidationBehavior.cs deleted file mode 100644 index 016652aeb..000000000 --- a/src/framework/Infrastructure/Behaviours/ValidationBehavior.cs +++ /dev/null @@ -1,23 +0,0 @@ -using FluentValidation; -using MediatR; - -namespace FSH.Framework.Infrastructure.Behaviours; -public class ValidationBehavior(IEnumerable> validators) : IPipelineBehavior - where TRequest : IRequest -{ - private readonly IEnumerable> _validators = validators; - - public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) - { - if (_validators.Any()) - { - var context = new ValidationContext(request); - var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken))); - var failures = validationResults.SelectMany(r => r.Errors).Where(f => f != null).ToList(); - - if (failures.Count > 0) - throw new ValidationException(failures); - } - return await next(); - } -} From 160e93a28a3835228963f6dd258fcf90c340ea3c Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 8 Apr 2025 18:46:54 +0530 Subject: [PATCH 07/54] fix --- src/framework/FSH.Framework.sln | 21 +++++++++++++++++++ .../Identity.Infrastructure/JwtOptions.cs | 2 +- .../Tenant/Tenant.Core/Tenant.Core.csproj | 12 +++++++++++ .../Tenant.Endpoints/Tenant.Endpoints.csproj | 14 +++++++++++++ .../Tenant.Infrastructure.csproj | 12 +++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/framework/Tenant/Tenant.Core/Tenant.Core.csproj create mode 100644 src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj create mode 100644 src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index c9352cdb5..51e0e2a5d 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -29,6 +29,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Endpoints", "Audit EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{09380C15-F138-4305-A595-F4C7E16B6E78}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Core", "Tenant\Tenant.Core\Tenant.Core.csproj", "{AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Endpoints", "Tenant\Tenant.Endpoints\Tenant.Endpoints.csproj", "{86BC889E-322A-460E-81B6-601EE65B37C1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Infrastructure", "Tenant\Tenant.Infrastructure\Tenant.Infrastructure.csproj", "{F8AE32F3-31B9-4962-BE7A-1326BD13B739}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -75,6 +81,18 @@ Global {09380C15-F138-4305-A595-F4C7E16B6E78}.Debug|Any CPU.Build.0 = Debug|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.ActiveCfg = Release|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.Build.0 = Release|Any CPU + {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Release|Any CPU.Build.0 = Release|Any CPU + {86BC889E-322A-460E-81B6-601EE65B37C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86BC889E-322A-460E-81B6-601EE65B37C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86BC889E-322A-460E-81B6-601EE65B37C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86BC889E-322A-460E-81B6-601EE65B37C1}.Release|Any CPU.Build.0 = Release|Any CPU + {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -86,5 +104,8 @@ Global {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2} = {E5141F38-2D08-44DA-9A6C-B96890515168} {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786} = {E5141F38-2D08-44DA-9A6C-B96890515168} {C8DCA061-E4D6-414F-9053-0723B6764D71} = {E5141F38-2D08-44DA-9A6C-B96890515168} + {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6} = {24E922E3-8C91-43A1-A110-D8F5276566BA} + {86BC889E-322A-460E-81B6-601EE65B37C1} = {24E922E3-8C91-43A1-A110-D8F5276566BA} + {F8AE32F3-31B9-4962-BE7A-1326BD13B739} = {24E922E3-8C91-43A1-A110-D8F5276566BA} EndGlobalSection EndGlobal diff --git a/src/framework/Identity/Identity.Infrastructure/JwtOptions.cs b/src/framework/Identity/Identity.Infrastructure/JwtOptions.cs index 8f5ff30ec..84dd1f57d 100644 --- a/src/framework/Identity/Identity.Infrastructure/JwtOptions.cs +++ b/src/framework/Identity/Identity.Infrastructure/JwtOptions.cs @@ -13,7 +13,7 @@ public IEnumerable Validate(ValidationContext validationContex { if (string.IsNullOrEmpty(Key)) { - yield return new ValidationResult("No Key defined in JwtSettings config", [nameof(Key)]); + yield return new ValidationResult("No Key defined in JwtOptions config", [nameof(Key)]); } } } diff --git a/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj b/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj new file mode 100644 index 000000000..1feb07015 --- /dev/null +++ b/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj @@ -0,0 +1,12 @@ + + + FSH.Framework.Tenant.Core + FSH.Framework.Tenant.Core + + + net9.0 + enable + enable + + + diff --git a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj new file mode 100644 index 000000000..15d657734 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj @@ -0,0 +1,14 @@ + + + FSH.Framework.Tenant.Endpoints + FSH.Framework.Tenant.Endpoints + + + net9.0 + enable + enable + + + + + diff --git a/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj b/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj new file mode 100644 index 000000000..ec7d897eb --- /dev/null +++ b/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj @@ -0,0 +1,12 @@ + + + FSH.Framework.Tenant.Infrastructure + FSH.Framework.Tenant.Infrastructure + + + net9.0 + enable + enable + + + From f7a54ceb356517bf0583d96a3f2d71bc048d8200 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 00:36:58 +0530 Subject: [PATCH 08/54] cleanup --- ...railDbContext.cs => IAuditingDbContext.cs} | 2 +- .../Data/AuditingDbContext.cs | 16 +++ .../Handlers/AuditPublishedEventHandler.cs | 2 +- .../Services/AuditService.cs | 2 +- .../Identity/Identity.Core/Dtos/UserDetail.cs | 4 +- .../Data/IdentityConfigurations.cs} | 10 +- .../Data}/IdentityDbContext.cs | 12 +- .../Data}/IdentityDbInitializer.cs | 11 +- .../Identity.Infrastructure.csproj | 6 + .../Identity.Infrastructure/Roles/FshRole.cs | 13 ++ .../Users}/CurrentUserService.cs | 10 +- .../Identity.Infrastructure}/Users/FshUser.cs | 2 +- .../Users}/UserService.Password.cs | 7 +- .../Users}/UserService.Permissions.cs | 2 - .../Users}/UserService.cs | 64 +++++---- .../Infrastructure/Infrastructure.csproj | 1 + .../Infrastructure/Persistence/Extensions.cs | 2 - .../Services/ConnectionStringValidator.cs | 2 +- .../Tenant/Abstractions/IFshTenantInfo.cs | 7 - .../Infrastructure/Tenant/Extensions.cs | 3 - src/framework/Shared/Constants/FshActions.cs | 13 ++ src/framework/Shared/Constants/FshClaims.cs | 10 ++ .../Shared/Constants/FshPermissions.cs | 66 +++++++++ .../Shared/Constants/FshResources.cs | 12 ++ src/framework/Shared/Constants/FshRoles.cs | 23 +++ .../Shared/Constants/TenantConstants.cs | 16 +++ .../Abstractions/IFshTenantInfo.cs | 5 + .../Data}/TenantDbContext.cs | 2 +- .../Tenant.Infrastructure/Extensions.cs | 132 ++++++++++++++++++ .../Tenant.Infrastructure}/FshTenantInfo.cs | 10 +- .../Tenant.Infrastructure.csproj | 12 +- .../Tenant.Infrastructure}/TenantService.cs | 6 +- 32 files changed, 397 insertions(+), 88 deletions(-) rename src/framework/Auditing/Auditing.Core/Abstractions/{IAuditTrailDbContext.cs => IAuditingDbContext.cs} (86%) create mode 100644 src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs rename src/framework/{Infrastructure/Identity/Persistence/IdentityConfiguration.cs => Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs} (87%) rename src/framework/{Infrastructure/Identity/Persistence => Identity/Identity.Infrastructure/Data}/IdentityDbContext.cs (78%) rename src/framework/{Infrastructure/Identity/Persistence => Identity/Identity.Infrastructure/Data}/IdentityDbInitializer.cs (93%) create mode 100644 src/framework/Identity/Identity.Infrastructure/Roles/FshRole.cs rename src/framework/{Infrastructure/Identity/Users/Services => Identity/Identity.Infrastructure/Users}/CurrentUserService.cs (80%) rename src/framework/{Infrastructure/Identity => Identity/Identity.Infrastructure}/Users/FshUser.cs (87%) rename src/framework/{Infrastructure/Identity/Users/Services => Identity/Identity.Infrastructure/Users}/UserService.Password.cs (87%) rename src/framework/{Infrastructure/Identity/Users/Services => Identity/Identity.Infrastructure/Users}/UserService.Permissions.cs (96%) rename src/framework/{Infrastructure/Identity/Users/Services => Identity/Identity.Infrastructure/Users}/UserService.cs (85%) delete mode 100644 src/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs create mode 100644 src/framework/Shared/Constants/FshActions.cs create mode 100644 src/framework/Shared/Constants/FshClaims.cs create mode 100644 src/framework/Shared/Constants/FshPermissions.cs create mode 100644 src/framework/Shared/Constants/FshResources.cs create mode 100644 src/framework/Shared/Constants/FshRoles.cs create mode 100644 src/framework/Shared/Constants/TenantConstants.cs create mode 100644 src/framework/Tenant/Tenant.Core/Abstractions/IFshTenantInfo.cs rename src/framework/{Infrastructure/Tenant/Persistence => Tenant/Tenant.Infrastructure/Data}/TenantDbContext.cs (91%) create mode 100644 src/framework/Tenant/Tenant.Infrastructure/Extensions.cs rename src/framework/{Infrastructure/Tenant => Tenant/Tenant.Infrastructure}/FshTenantInfo.cs (89%) rename src/framework/{Infrastructure/Tenant/Services => Tenant/Tenant.Infrastructure}/TenantService.cs (95%) diff --git a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditTrailDbContext.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs similarity index 86% rename from src/framework/Auditing/Auditing.Core/Abstractions/IAuditTrailDbContext.cs rename to src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs index e43213ab4..6744f15e1 100644 --- a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditTrailDbContext.cs +++ b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs @@ -2,7 +2,7 @@ using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Auditing.Core.Abstractions; -public interface IAuditTrailDbContext +public interface IAuditingDbContext { DbSet AuditTrails { get; } Task SaveChangesAsync(CancellationToken cancellationToken); diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs new file mode 100644 index 000000000..68080b2a9 --- /dev/null +++ b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs @@ -0,0 +1,16 @@ +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Auditing.Core.Dtos; +using Microsoft.EntityFrameworkCore; + +namespace FSH.Framework.Auditing.Infrastructure.Data; +public class AuditingDbContext : DbContext, IAuditingDbContext +{ + public DbSet AuditTrails { get; set; } + + public AuditingDbContext(DbContextOptions options) : base(options) { } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfigurationsFromAssembly(typeof(AuditingDbContext).Assembly); + } +} diff --git a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs index 8c43ec988..971fa98c1 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs @@ -8,7 +8,7 @@ namespace FSH.Framework.Auditing.Infrastructure.Handlers; public class AuditPublishedEventHandler( ILogger logger, - IAuditTrailDbContext context) + IAuditingDbContext context) : INotificationHandler { public async Task Handle(AuditPublishedEvent notification, CancellationToken cancellationToken) diff --git a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs index f9944feb2..677f582d6 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Auditing.Infrastructure.Services; -public class AuditService(IAuditTrailDbContext context) : IAuditService +public class AuditService(IAuditingDbContext context) : IAuditService { public async Task> GetUserTrailsAsync(Guid userId) { diff --git a/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs b/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs index 92b2c5cf3..4888e6031 100644 --- a/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs +++ b/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs @@ -1,7 +1,7 @@ namespace FSH.Framework.Identity.Core.Dtos; public class UserDetail { - public Guid Id { get; set; } + public string? Id { get; set; } public string? UserName { get; set; } @@ -17,5 +17,5 @@ public class UserDetail public string? PhoneNumber { get; set; } - public Uri? ImageUrl { get; set; } + public string? ImageUrl { get; set; } } diff --git a/src/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs b/src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs similarity index 87% rename from src/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs rename to src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs index 240b63fff..83e2c4c38 100644 --- a/src/framework/Infrastructure/Identity/Persistence/IdentityConfiguration.cs +++ b/src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs @@ -1,14 +1,10 @@ -using Finbuckle.MultiTenant; -using FSH.Framework.Core.Audit; -using FSH.Framework.Infrastructure.Identity.RoleClaims; -using FSH.Framework.Infrastructure.Identity.Roles; -using FSH.Framework.Infrastructure.Identity.Users; +using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Identity.Infrastructure.Users; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using IdentityConstants = FSH.Starter.Shared.Authorization.IdentityConstants; -namespace FSH.Framework.Infrastructure.Identity.Persistence; +namespace FSH.Framework.Identity.Infrastructure.Data; public class AuditTrailConfig : IEntityTypeConfiguration { diff --git a/src/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs similarity index 78% rename from src/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs rename to src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs index 5945567c3..4ba21bfaf 100644 --- a/src/framework/Infrastructure/Identity/Persistence/IdentityDbContext.cs +++ b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs @@ -1,17 +1,13 @@ using Finbuckle.MultiTenant.Abstractions; using Finbuckle.MultiTenant.EntityFrameworkCore; -using FSH.Framework.Core.Audit; using FSH.Framework.Core.Persistence; -using FSH.Framework.Infrastructure.Identity.RoleClaims; -using FSH.Framework.Infrastructure.Identity.Roles; -using FSH.Framework.Infrastructure.Identity.Users; -using FSH.Framework.Infrastructure.Persistence; -using FSH.Framework.Infrastructure.Tenant; +using FSH.Framework.Identity.Infrastructure.Roles; +using FSH.Framework.Identity.Infrastructure.Users; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; -namespace FSH.Framework.Infrastructure.Identity.Persistence; +namespace FSH.Framework.Identity.Infrastructure.Data; public class IdentityDbContext : MultiTenantIdentityDbContext multiTenantC TenantInfo = multiTenantContextAccessor.MultiTenantContext.TenantInfo!; } - public DbSet AuditTrails { get; set; } - protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); diff --git a/src/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs similarity index 93% rename from src/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs rename to src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs index f4759350c..0369630fb 100644 --- a/src/framework/Infrastructure/Identity/Persistence/IdentityDbInitializer.cs +++ b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs @@ -1,18 +1,15 @@ using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Origin; using FSH.Framework.Core.Persistence; -using FSH.Framework.Infrastructure.Identity.RoleClaims; -using FSH.Framework.Infrastructure.Identity.Roles; -using FSH.Framework.Infrastructure.Identity.Users; -using FSH.Framework.Infrastructure.Tenant; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Infrastructure.Roles; +using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Shared.Constants; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using IdentityConstants = FSH.Starter.Shared.Authorization.IdentityConstants; -namespace FSH.Framework.Infrastructure.Identity.Persistence; +namespace FSH.Framework.Identity.Infrastructure.Data; internal sealed class IdentityDbInitializer( ILogger logger, IdentityDbContext context, diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index f4e2960b9..3f2a5bb3f 100644 --- a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -9,6 +9,8 @@ enable + + @@ -17,5 +19,9 @@ + + + + diff --git a/src/framework/Identity/Identity.Infrastructure/Roles/FshRole.cs b/src/framework/Identity/Identity.Infrastructure/Roles/FshRole.cs new file mode 100644 index 000000000..cb7501d0e --- /dev/null +++ b/src/framework/Identity/Identity.Infrastructure/Roles/FshRole.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Identity; +namespace FSH.Framework.Identity.Infrastructure.Roles; +public class FshRole : IdentityRole +{ + public string? Description { get; set; } + + public FshRole(string name, string? description = null) + : base(name) + { + Description = description; + NormalizedName = name.ToUpperInvariant(); + } +} diff --git a/src/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs b/src/framework/Identity/Identity.Infrastructure/Users/CurrentUserService.cs similarity index 80% rename from src/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs rename to src/framework/Identity/Identity.Infrastructure/Users/CurrentUserService.cs index 9c67edc36..362eef171 100644 --- a/src/framework/Infrastructure/Identity/Users/Services/CurrentUserService.cs +++ b/src/framework/Identity/Identity.Infrastructure/Users/CurrentUserService.cs @@ -1,10 +1,10 @@ using System.Security.Claims; using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.ExecutionContext; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Extensions; -namespace FSH.Framework.Infrastructure.Identity.Users.Services; +namespace FSH.Framework.Identity.Infrastructure.Users; public class CurrentUser : ICurrentUser, ICurrentUserInitializer { private ClaimsPrincipal? _user; @@ -41,7 +41,7 @@ public void SetCurrentUser(ClaimsPrincipal user) { if (_user != null) { - throw new FshException("Method reserved for in-scope initialization"); + throw new CustomException("Method reserved for in-scope initialization"); } _user = user; @@ -51,7 +51,7 @@ public void SetCurrentUserId(string userId) { if (_userId != Guid.Empty) { - throw new FshException("Method reserved for in-scope initialization"); + throw new CustomException("Method reserved for in-scope initialization"); } if (!string.IsNullOrEmpty(userId)) diff --git a/src/framework/Infrastructure/Identity/Users/FshUser.cs b/src/framework/Identity/Identity.Infrastructure/Users/FshUser.cs similarity index 87% rename from src/framework/Infrastructure/Identity/Users/FshUser.cs rename to src/framework/Identity/Identity.Infrastructure/Users/FshUser.cs index 4d68e207f..f9c3e7ded 100644 --- a/src/framework/Infrastructure/Identity/Users/FshUser.cs +++ b/src/framework/Identity/Identity.Infrastructure/Users/FshUser.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Identity; -namespace FSH.Framework.Infrastructure.Identity.Users; +namespace FSH.Framework.Identity.Infrastructure.Users; public class FshUser : IdentityUser { public string? FirstName { get; set; } diff --git a/src/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs b/src/framework/Identity/Identity.Infrastructure/Users/UserService.Password.cs similarity index 87% rename from src/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs rename to src/framework/Identity/Identity.Infrastructure/Users/UserService.Password.cs index 97b7af797..6deb6db0c 100644 --- a/src/framework/Infrastructure/Identity/Users/Services/UserService.Password.cs +++ b/src/framework/Identity/Identity.Infrastructure/Users/UserService.Password.cs @@ -1,9 +1,6 @@ using System.Collections.ObjectModel; using System.Text; using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.Identity.Users.Features.ChangePassword; -using FSH.Framework.Core.Identity.Users.Features.ForgotPassword; -using FSH.Framework.Core.Identity.Users.Features.ResetPassword; using FSH.Framework.Core.Mail; using Microsoft.AspNetCore.WebUtilities; @@ -53,7 +50,7 @@ public async Task ResetPasswordAsync(ResetPasswordCommand request, CancellationT if (!result.Succeeded) { var errors = result.Errors.Select(e => e.Description).ToList(); - throw new FshException("error resetting password", errors); + throw new CustomException("error resetting password", errors); } } @@ -68,7 +65,7 @@ public async Task ChangePasswordAsync(ChangePasswordCommand request, string user if (!result.Succeeded) { var errors = result.Errors.Select(e => e.Description).ToList(); - throw new FshException("failed to change password", errors); + throw new CustomException("failed to change password", errors); } } } diff --git a/src/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs b/src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs similarity index 96% rename from src/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs rename to src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs index 52f5698f7..d150028a6 100644 --- a/src/framework/Infrastructure/Identity/Users/Services/UserService.Permissions.cs +++ b/src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs @@ -1,7 +1,5 @@ using FSH.Framework.Core.Caching; using FSH.Framework.Core.Exceptions; -using FSH.Starter.Shared.Authorization; -using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Infrastructure.Identity.Users.Services; internal sealed partial class UserService diff --git a/src/framework/Infrastructure/Identity/Users/Services/UserService.cs b/src/framework/Identity/Identity.Infrastructure/Users/UserService.cs similarity index 85% rename from src/framework/Infrastructure/Identity/Users/Services/UserService.cs rename to src/framework/Identity/Identity.Infrastructure/Users/UserService.cs index a714a154d..5040fb33e 100644 --- a/src/framework/Infrastructure/Identity/Users/Services/UserService.cs +++ b/src/framework/Identity/Identity.Infrastructure/Users/UserService.cs @@ -1,25 +1,17 @@ using System.Collections.ObjectModel; using System.Security.Claims; using System.Text; -using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Caching; using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.Identity.Users.Abstractions; using FSH.Framework.Core.Identity.Users.Dtos; -using FSH.Framework.Core.Identity.Users.Features.AssignUserRole; -using FSH.Framework.Core.Identity.Users.Features.RegisterUser; -using FSH.Framework.Core.Identity.Users.Features.ToggleUserStatus; -using FSH.Framework.Core.Identity.Users.Features.UpdateUser; using FSH.Framework.Core.Jobs; using FSH.Framework.Core.Mail; using FSH.Framework.Core.Storage; -using FSH.Framework.Core.Storage.File; -using FSH.Framework.Infrastructure.Constants; -using FSH.Framework.Infrastructure.Identity.Persistence; -using FSH.Framework.Infrastructure.Identity.Roles; -using FSH.Framework.Infrastructure.Tenant; -using FSH.Starter.Shared.Authorization; -using Mapster; +using FSH.Framework.Identity.Core.Dtos; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Infrastructure.Roles; +using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Shared.Constants; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.WebUtilities; using Microsoft.EntityFrameworkCore; @@ -54,14 +46,14 @@ public async Task ConfirmEmailAsync(string userId, string code, string t .Where(u => u.Id == userId && !u.EmailConfirmed) .FirstOrDefaultAsync(cancellationToken); - _ = user ?? throw new FshException("An error occurred while confirming E-Mail."); + _ = user ?? throw new CustomException("An error occurred while confirming E-Mail."); code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); var result = await userManager.ConfirmEmailAsync(user, code); return result.Succeeded ? string.Format("Account Confirmed for E-Mail {0}. You can now use the /api/tokens endpoint to generate JWT.", user.Email) - : throw new FshException(string.Format("An error occurred while confirming {0}", user.Email)); + : throw new CustomException(string.Format("An error occurred while confirming {0}", user.Email)); } public Task ConfirmPhoneNumberAsync(string userId, string code) @@ -96,7 +88,16 @@ public async Task GetAsync(string userId, CancellationToken cancella _ = user ?? throw new NotFoundException("user not found"); - return user.Adapt(); + return new UserDetail + { + Id = user.Id, + Email = user.Email, + UserName = user.UserName, + FirstName = user.FirstName, + LastName = user.LastName, + ImageUrl = user.ImageUrl?.ToString(), + IsActive = user.IsActive + }; } public Task GetCountAsync(CancellationToken cancellationToken) => @@ -105,7 +106,22 @@ public Task GetCountAsync(CancellationToken cancellationToken) => public async Task> GetListAsync(CancellationToken cancellationToken) { var users = await userManager.Users.AsNoTracking().ToListAsync(cancellationToken); - return users.Adapt>(); + var result = new List(users.Count); + foreach (var user in users) + { + result.Add(new UserDetail + { + Id = user.Id, + Email = user.Email, + UserName = user.UserName, + FirstName = user.FirstName, + LastName = user.LastName, + ImageUrl = user.ImageUrl?.ToString(), + IsActive = user.IsActive + }); + } + + return result; } public Task GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal) @@ -133,7 +149,7 @@ public async Task RegisterAsync(RegisterUserCommand reques if (!result.Succeeded) { var errors = result.Errors.Select(error => error.Description).ToList(); - throw new FshException("error while registering a new user", errors); + throw new CustomException("error while registering a new user", errors); } // add basic role @@ -162,7 +178,7 @@ public async Task ToggleStatusAsync(ToggleUserStatusCommand request, Cancellatio bool isAdmin = await userManager.IsInRoleAsync(user, FshRoles.Admin); if (isAdmin) { - throw new FshException("Administrators Profile's Status cannot be toggled"); + throw new CustomException("Administrators Profile's Status cannot be toggled"); } user.IsActive = request.ActivateUser; @@ -182,7 +198,7 @@ public async Task UpdateAsync(UpdateUserCommand request, string userId) user.ImageUrl = await storageService.UploadAsync(request.Image, FileType.Image); if (request.DeleteCurrentImage && imageUri != null) { - storageService.Remove(imageUri); + await storageService.RemoveAsync(imageUri.ToString()); } } @@ -200,7 +216,7 @@ public async Task UpdateAsync(UpdateUserCommand request, string userId) if (!result.Succeeded) { - throw new FshException("Update profile failed"); + throw new CustomException("Update profile failed"); } } @@ -216,7 +232,7 @@ public async Task DeleteAsync(string userId) if (!result.Succeeded) { List errors = result.Errors.Select(error => error.Description).ToList(); - throw new FshException("Delete profile failed", errors); + throw new CustomException("Delete profile failed", errors); } } @@ -257,12 +273,12 @@ public async Task AssignRolesAsync(string userId, AssignUserRoleCommand { if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id == TenantConstants.Root.Id) { - throw new FshException("action not permitted"); + throw new CustomException("action not permitted"); } } else if (adminCount <= 2) { - throw new FshException("tenant should have at least 2 admins."); + throw new CustomException("tenant should have at least 2 admins."); } } diff --git a/src/framework/Infrastructure/Infrastructure.csproj b/src/framework/Infrastructure/Infrastructure.csproj index b258efd7c..4a5210eff 100644 --- a/src/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Infrastructure/Infrastructure.csproj @@ -7,6 +7,7 @@ + diff --git a/src/framework/Infrastructure/Persistence/Extensions.cs b/src/framework/Infrastructure/Persistence/Extensions.cs index dce8cb5a6..bfbd1270f 100644 --- a/src/framework/Infrastructure/Persistence/Extensions.cs +++ b/src/framework/Infrastructure/Persistence/Extensions.cs @@ -1,5 +1,4 @@ using FSH.Framework.Core.Persistence; -using FSH.Framework.Infrastructure.Persistence.Interceptors; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; @@ -36,7 +35,6 @@ public static WebApplicationBuilder ConfigureDatabase(this WebApplicationBuilder Logger.Information("for documentations and guides, visit https://www.fullstackhero.net"); Logger.Information("to sponsor this project, visit https://opencollective.com/fullstackhero"); }); - builder.Services.AddScoped(); return builder; } diff --git a/src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs b/src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs index 2b39de48d..f12b3aba2 100644 --- a/src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs +++ b/src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs @@ -5,7 +5,7 @@ using Npgsql; namespace FSH.Framework.Infrastructure.Persistence.Services; -internal sealed class ConnectionStringValidator(IOptions dbSettings, ILogger logger) : IConnectionStringValidator +public sealed class ConnectionStringValidator(IOptions dbSettings, ILogger logger) : IConnectionStringValidator { private readonly DatabaseOptions _dbSettings = dbSettings.Value; private readonly ILogger _logger = logger; diff --git a/src/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs b/src/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs deleted file mode 100644 index 843820200..000000000 --- a/src/framework/Infrastructure/Tenant/Abstractions/IFshTenantInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Finbuckle.MultiTenant.Abstractions; - -namespace FSH.Framework.Infrastructure.Tenant.Abstractions; -public interface IFshTenantInfo : ITenantInfo -{ - string? ConnectionString { get; set; } -} diff --git a/src/framework/Infrastructure/Tenant/Extensions.cs b/src/framework/Infrastructure/Tenant/Extensions.cs index f7fea460c..f5e3fe398 100644 --- a/src/framework/Infrastructure/Tenant/Extensions.cs +++ b/src/framework/Infrastructure/Tenant/Extensions.cs @@ -5,9 +5,6 @@ using FSH.Framework.Core.Tenant.Abstractions; using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Infrastructure.Persistence.Services; -using FSH.Framework.Infrastructure.Tenant.Persistence; -using FSH.Framework.Infrastructure.Tenant.Services; -using FSH.Starter.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; diff --git a/src/framework/Shared/Constants/FshActions.cs b/src/framework/Shared/Constants/FshActions.cs new file mode 100644 index 000000000..77d873fae --- /dev/null +++ b/src/framework/Shared/Constants/FshActions.cs @@ -0,0 +1,13 @@ +namespace FSH.Framework.Shared.Constants; +public static class FshActions +{ + public const string View = nameof(View); + public const string Search = nameof(Search); + public const string Create = nameof(Create); + public const string Update = nameof(Update); + public const string Delete = nameof(Delete); + public const string Export = nameof(Export); + public const string Generate = nameof(Generate); + public const string Clean = nameof(Clean); + public const string UpgradeSubscription = nameof(UpgradeSubscription); +} diff --git a/src/framework/Shared/Constants/FshClaims.cs b/src/framework/Shared/Constants/FshClaims.cs new file mode 100644 index 000000000..11b2eeead --- /dev/null +++ b/src/framework/Shared/Constants/FshClaims.cs @@ -0,0 +1,10 @@ +namespace FSH.Framework.Shared.Constants; +public static class FshClaims +{ + public const string Tenant = "tenant"; + public const string Fullname = "fullName"; + public const string Permission = "permission"; + public const string ImageUrl = "image_url"; + public const string IpAddress = "ipAddress"; + public const string Expiration = "exp"; +} diff --git a/src/framework/Shared/Constants/FshPermissions.cs b/src/framework/Shared/Constants/FshPermissions.cs new file mode 100644 index 000000000..6bdd7805b --- /dev/null +++ b/src/framework/Shared/Constants/FshPermissions.cs @@ -0,0 +1,66 @@ +namespace FSH.Framework.Shared.Constants; + +public static class FshPermissions +{ + private static readonly List _all = new() + { + // Built-in permissions + + // Tenants + new("View Tenants", FshActions.View, FshResources.Tenants, IsRoot: true), + new("Create Tenants", FshActions.Create, FshResources.Tenants, IsRoot: true), + new("Update Tenants", FshActions.Update, FshResources.Tenants, IsRoot: true), + new("Upgrade Tenant Subscription", FshActions.UpgradeSubscription, FshResources.Tenants, IsRoot: true), + + // Identity + new("View Users", FshActions.View, FshResources.Users), + new("Search Users", FshActions.Search, FshResources.Users), + new("Create Users", FshActions.Create, FshResources.Users), + new("Update Users", FshActions.Update, FshResources.Users), + new("Delete Users", FshActions.Delete, FshResources.Users), + new("Export Users", FshActions.Export, FshResources.Users), + new("View UserRoles", FshActions.View, FshResources.UserRoles), + new("Update UserRoles", FshActions.Update, FshResources.UserRoles), + new("View Roles", FshActions.View, FshResources.Roles), + new("Create Roles", FshActions.Create, FshResources.Roles), + new("Update Roles", FshActions.Update, FshResources.Roles), + new("Delete Roles", FshActions.Delete, FshResources.Roles), + new("View RoleClaims", FshActions.View, FshResources.RoleClaims), + new("Update RoleClaims", FshActions.Update, FshResources.RoleClaims), + + // Audit + new("View Audit Trails", FshActions.View, FshResources.AuditTrails), + + // Hangfire / Dashboard + new("View Hangfire", FshActions.View, FshResources.Hangfire), + new("View Dashboard", FshActions.View, FshResources.Dashboard), + }; + + /// + /// Register additional permissions from external projects/modules. + /// + public static void Register(IEnumerable additionalPermissions) + { + foreach (var permission in additionalPermissions) + { + if (!_all.Any(p => p.Name == permission.Name)) + _all.Add(permission); + } + } + + public static IReadOnlyList All => _all.AsReadOnly(); + public static IReadOnlyList Root => _all.Where(p => p.IsRoot).ToList(); + public static IReadOnlyList Admin => _all.Where(p => !p.IsRoot).ToList(); + public static IReadOnlyList Basic => _all.Where(p => p.IsBasic).ToList(); +} + +public record FshPermission(string Description, string Action, string Resource, bool IsBasic = false, bool IsRoot = false) +{ + public string Name => NameFor(Action, Resource); + public static string NameFor(string action, string resource) + { + return $"Permissions.{resource}.{action}"; + } +} + + diff --git a/src/framework/Shared/Constants/FshResources.cs b/src/framework/Shared/Constants/FshResources.cs new file mode 100644 index 000000000..9e74f2ac6 --- /dev/null +++ b/src/framework/Shared/Constants/FshResources.cs @@ -0,0 +1,12 @@ +namespace FSH.Framework.Shared.Constants; +public static class FshResources +{ + public const string Tenants = nameof(Tenants); + public const string Dashboard = nameof(Dashboard); + public const string Hangfire = nameof(Hangfire); + public const string Users = nameof(Users); + public const string UserRoles = nameof(UserRoles); + public const string Roles = nameof(Roles); + public const string RoleClaims = nameof(RoleClaims); + public const string AuditTrails = nameof(AuditTrails); +} diff --git a/src/framework/Shared/Constants/FshRoles.cs b/src/framework/Shared/Constants/FshRoles.cs new file mode 100644 index 000000000..8b8b6bc1a --- /dev/null +++ b/src/framework/Shared/Constants/FshRoles.cs @@ -0,0 +1,23 @@ +using System.Collections.ObjectModel; + +namespace FSH.Framework.Shared.Constants; + +public static class FshRoles +{ + public const string Admin = nameof(Admin); + public const string Basic = nameof(Basic); + + /// + /// The base roles provided by the framework. + /// + public static IReadOnlyList DefaultRoles { get; } = new ReadOnlyCollection(new[] + { + Admin, + Basic + }); + + /// + /// Determines whether the role is a framework-defined default. + /// + public static bool IsDefault(string roleName) => DefaultRoles.Contains(roleName); +} diff --git a/src/framework/Shared/Constants/TenantConstants.cs b/src/framework/Shared/Constants/TenantConstants.cs new file mode 100644 index 000000000..0d1584886 --- /dev/null +++ b/src/framework/Shared/Constants/TenantConstants.cs @@ -0,0 +1,16 @@ +namespace FSH.Framework.Shared.Constants; +public static class TenantConstants +{ + public static class Root + { + public const string Id = "root"; + public const string Name = "Root"; + public const string EmailAddress = "admin@root.com"; + public const string DefaultProfilePicture = "assets/defaults/profile-picture.webp"; + } + + public const string DefaultPassword = "123Pa$$word!"; + + public const string Identifier = "tenant"; + +} diff --git a/src/framework/Tenant/Tenant.Core/Abstractions/IFshTenantInfo.cs b/src/framework/Tenant/Tenant.Core/Abstractions/IFshTenantInfo.cs new file mode 100644 index 000000000..d2a7cdad3 --- /dev/null +++ b/src/framework/Tenant/Tenant.Core/Abstractions/IFshTenantInfo.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Tenant.Core.Abstractions; +public interface IFshTenantInfo +{ + string? ConnectionString { get; set; } +} diff --git a/src/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs b/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs similarity index 91% rename from src/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs rename to src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs index d778a7ce5..c350ddb85 100644 --- a/src/framework/Infrastructure/Tenant/Persistence/TenantDbContext.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs @@ -1,7 +1,7 @@ using Finbuckle.MultiTenant.EntityFrameworkCore.Stores.EFCoreStore; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Infrastructure.Tenant.Persistence; +namespace FSH.Framework.Tenant.Infrastructure.Data; public class TenantDbContext : EFCoreStoreDbContext { public const string Schema = "tenant"; diff --git a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs new file mode 100644 index 000000000..d5c48d82f --- /dev/null +++ b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs @@ -0,0 +1,132 @@ +using Finbuckle.MultiTenant; +using Finbuckle.MultiTenant.Abstractions; +using Finbuckle.MultiTenant.Stores.DistributedCacheStore; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Core.Tenant.Abstractions; +using FSH.Framework.Infrastructure.Persistence; +using FSH.Framework.Infrastructure.Persistence.Services; +using FSH.Framework.Shared.Constants; +using FSH.Framework.Tenant.Infrastructure.Data; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Tenant.Infrastructure; +internal static class Extensions +{ + public static IServiceCollection ConfigureMultitenancy(this IServiceCollection services) + { + ArgumentNullException.ThrowIfNull(services); + services.AddTransient(); + services.BindDbContext(); + services + .AddMultiTenant(config => + { + // to save database calls to resolve tenant + // this was happening for every request earlier, leading to ineffeciency + config.Events.OnTenantResolveCompleted = async (context) => + { + if (context.MultiTenantContext.StoreInfo is null) return; + if (context.MultiTenantContext.StoreInfo.StoreType != typeof(DistributedCacheStore)) + { + var sp = ((HttpContext)context.Context!).RequestServices; + var distributedCacheStore = sp + .GetService>>()! + .FirstOrDefault(s => s.GetType() == typeof(DistributedCacheStore)); + + await distributedCacheStore!.TryAddAsync(context.MultiTenantContext.TenantInfo!); + } + await Task.FromResult(0); + }; + }) + .WithClaimStrategy(FshClaims.Tenant) + .WithHeaderStrategy(TenantConstants.Identifier) + .WithDelegateStrategy(async context => + { + if (context is not HttpContext httpContext) + return null; + if (!httpContext.Request.Query.TryGetValue(FshClaims.Tenant, out var tenantIdentifier) || string.IsNullOrEmpty(tenantIdentifier)) + return null; + return await Task.FromResult(tenantIdentifier.ToString()); + }) + .WithDistributedCacheStore(TimeSpan.FromMinutes(60)) + .WithEFCoreStore(); + services.AddScoped(); + return services; + } + + public static WebApplication UseMultitenancy(this WebApplication app) + { + ArgumentNullException.ThrowIfNull(app); + app.UseMultiTenant(); + + // set up tenant store + var tenants = TenantStoreSetup(app); + + // set up tenant databases + app.SetupTenantDatabases(tenants); + + return app; + } + + private static IApplicationBuilder SetupTenantDatabases(this IApplicationBuilder app, IEnumerable tenants) + { + foreach (var tenant in tenants) + { + // create a scope for tenant + using var tenantScope = app.ApplicationServices.CreateScope(); + + //set current tenant so that the right connection string is used + tenantScope.ServiceProvider.GetRequiredService() + .MultiTenantContext = new MultiTenantContext() + { + TenantInfo = tenant + }; + + // using the scope, perform migrations / seeding + var initializers = tenantScope.ServiceProvider.GetServices(); + foreach (var initializer in initializers) + { + initializer.MigrateAsync(CancellationToken.None).Wait(); + initializer.SeedAsync(CancellationToken.None).Wait(); + } + } + return app; + } + + private static IEnumerable TenantStoreSetup(IApplicationBuilder app) + { + var scope = app.ApplicationServices.CreateScope(); + + // tenant master schema migration + var tenantDbContext = scope.ServiceProvider.GetRequiredService(); + if (tenantDbContext.Database.GetPendingMigrations().Any()) + { + tenantDbContext.Database.Migrate(); + } + + // default tenant seeding + if (tenantDbContext.TenantInfo.Find(TenantConstants.Root.Id) is null) + { + var rootTenant = new FshTenantInfo( + TenantConstants.Root.Id, + TenantConstants.Root.Name, + string.Empty, + TenantConstants.Root.EmailAddress); + + rootTenant.SetValidity(DateTime.UtcNow.AddYears(1)); + tenantDbContext.TenantInfo.Add(rootTenant); + tenantDbContext.SaveChanges(); + } + + // get all tenants from store + var tenantStore = scope.ServiceProvider.GetRequiredService>(); + var tenants = tenantStore.GetAllAsync().Result; + + //dispose scope + scope.Dispose(); + + return tenants; + } +} diff --git a/src/framework/Infrastructure/Tenant/FshTenantInfo.cs b/src/framework/Tenant/Tenant.Infrastructure/FshTenantInfo.cs similarity index 89% rename from src/framework/Infrastructure/Tenant/FshTenantInfo.cs rename to src/framework/Tenant/Tenant.Infrastructure/FshTenantInfo.cs index 7be7d62d3..e102b040e 100644 --- a/src/framework/Infrastructure/Tenant/FshTenantInfo.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/FshTenantInfo.cs @@ -1,10 +1,10 @@ using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Exceptions; -using FSH.Framework.Infrastructure.Tenant.Abstractions; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Shared.Constants; +using FSH.Framework.Tenant.Core.Abstractions; -namespace FSH.Framework.Infrastructure.Tenant; -public sealed class FshTenantInfo : IFshTenantInfo +namespace FSH.Framework.Tenant.Infrastructure; +public class FshTenantInfo : ITenantInfo, IFshTenantInfo { public FshTenantInfo() { @@ -40,7 +40,7 @@ public void AddValidity(int months) => public void SetValidity(in DateTime validTill) => ValidUpto = ValidUpto < validTill ? validTill - : throw new FshException("Subscription cannot be backdated."); + : throw new CustomException("Subscription cannot be backdated."); public void Activate() { diff --git a/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj b/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj index ec7d897eb..7774cd70c 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj +++ b/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj @@ -8,5 +8,15 @@ enable enable - + + + + + + + + + + + diff --git a/src/framework/Infrastructure/Tenant/Services/TenantService.cs b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs similarity index 95% rename from src/framework/Infrastructure/Tenant/Services/TenantService.cs rename to src/framework/Tenant/Tenant.Infrastructure/TenantService.cs index bfc8458cf..9e087cf54 100644 --- a/src/framework/Infrastructure/Tenant/Services/TenantService.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -namespace FSH.Framework.Infrastructure.Tenant.Services; +namespace FSH.Framework.Tenant.Infrastructure; public sealed class TenantService : ITenantService { @@ -30,7 +30,7 @@ public async Task ActivateAsync(string id, CancellationToken cancellatio if (tenant.IsActive) { - throw new FshException($"tenant {id} is already activated"); + throw new CustomException($"tenant {id} is already activated"); } tenant.Activate(); @@ -82,7 +82,7 @@ public async Task DeactivateAsync(string id) var tenant = await GetTenantInfoAsync(id).ConfigureAwait(false); if (!tenant.IsActive) { - throw new FshException($"tenant {id} is already deactivated"); + throw new CustomException($"tenant {id} is already deactivated"); } tenant.Deactivate(); From c0a993cf65fc0f1bd899ff01f19cc55e5da968e6 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 12:35:35 +0530 Subject: [PATCH 09/54] custom cqrs --- src/Directory.Packages.props | 1 + src/framework/Core/CQRS/ICommand.cs | 4 +++ src/framework/Core/CQRS/ICommandDispatcher.cs | 9 ++++++ src/framework/Core/CQRS/ICommandHandler.cs | 12 ++++++++ src/framework/Core/CQRS/IQuery.cs | 4 +++ src/framework/Core/CQRS/IQueryDispatcher.cs | 9 ++++++ src/framework/Core/CQRS/IQueryHandler.cs | 12 ++++++++ src/framework/Core/CQRS/IRequest.cs | 4 +++ ...quiredPermissionAuthorizationExtensions.cs | 4 +-- .../Identity.Infrastructure.csproj | 1 - .../Infrastructure/CQRS/CommandDispatcher.cs | 20 +++++++++++++ .../Infrastructure/CQRS/Extensions.cs | 29 +++++++++++++++++++ .../Infrastructure/CQRS/QueryDispatcher.cs | 20 +++++++++++++ .../Infrastructure/Infrastructure.csproj | 1 + .../Constants/AuthenticationConstants.cs | 5 ++++ .../Abstractions/ITenantService.cs | 20 +++++++++++++ .../Activate/ActivateTenantCommand.cs | 4 +++ .../Tenant.Endpoints/Tenant.Endpoints.csproj | 4 +++ .../v1/Activate}/ActivateTenantEndpoint.cs | 6 ++-- .../v1}/CreateTenantEndpoint.cs | 0 .../v1}/DisableTenantEndpoint.cs | 0 .../Tenant.Endpoints/v1}/Extensions.cs | 3 +- .../v1}/GetTenantByIdEndpoint.cs | 0 .../v1}/GetTenantsEndpoint.cs | 0 .../v1}/UpgradeSubscriptionEndpoint.cs | 0 .../Tenant.Infrastructure/Extensions.cs | 1 + .../Tenant.Infrastructure/TenantService.cs | 1 + 27 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 src/framework/Core/CQRS/ICommand.cs create mode 100644 src/framework/Core/CQRS/ICommandDispatcher.cs create mode 100644 src/framework/Core/CQRS/ICommandHandler.cs create mode 100644 src/framework/Core/CQRS/IQuery.cs create mode 100644 src/framework/Core/CQRS/IQueryDispatcher.cs create mode 100644 src/framework/Core/CQRS/IQueryHandler.cs create mode 100644 src/framework/Core/CQRS/IRequest.cs create mode 100644 src/framework/Infrastructure/CQRS/CommandDispatcher.cs create mode 100644 src/framework/Infrastructure/CQRS/Extensions.cs create mode 100644 src/framework/Infrastructure/CQRS/QueryDispatcher.cs create mode 100644 src/framework/Shared/Constants/AuthenticationConstants.cs create mode 100644 src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs create mode 100644 src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs rename src/framework/{Infrastructure/Tenant/Endpoints => Tenant/Tenant.Endpoints/v1/Activate}/ActivateTenantEndpoint.cs (79%) rename src/framework/{Infrastructure/Tenant/Endpoints => Tenant/Tenant.Endpoints/v1}/CreateTenantEndpoint.cs (100%) rename src/framework/{Infrastructure/Tenant/Endpoints => Tenant/Tenant.Endpoints/v1}/DisableTenantEndpoint.cs (100%) rename src/framework/{Infrastructure/Tenant/Endpoints => Tenant/Tenant.Endpoints/v1}/Extensions.cs (88%) rename src/framework/{Infrastructure/Tenant/Endpoints => Tenant/Tenant.Endpoints/v1}/GetTenantByIdEndpoint.cs (100%) rename src/framework/{Infrastructure/Tenant/Endpoints => Tenant/Tenant.Endpoints/v1}/GetTenantsEndpoint.cs (100%) rename src/framework/{Infrastructure/Tenant/Endpoints => Tenant/Tenant.Endpoints/v1}/UpgradeSubscriptionEndpoint.cs (100%) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index a1d8d0705..b45d4cd42 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -38,6 +38,7 @@ + diff --git a/src/framework/Core/CQRS/ICommand.cs b/src/framework/Core/CQRS/ICommand.cs new file mode 100644 index 000000000..1f0baad0f --- /dev/null +++ b/src/framework/Core/CQRS/ICommand.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Core.CQRS; + +// Marker for command requests (intended to modify system state) +public interface ICommand : IRequest { } diff --git a/src/framework/Core/CQRS/ICommandDispatcher.cs b/src/framework/Core/CQRS/ICommandDispatcher.cs new file mode 100644 index 000000000..c308d2efc --- /dev/null +++ b/src/framework/Core/CQRS/ICommandDispatcher.cs @@ -0,0 +1,9 @@ +namespace FSH.Framework.Core.CQRS; +public interface ICommandDispatcher +{ + /// + /// Sends a command to its handler. + /// + Task SendAsync(TCommand command, CancellationToken ct = default) + where TCommand : ICommand; +} diff --git a/src/framework/Core/CQRS/ICommandHandler.cs b/src/framework/Core/CQRS/ICommandHandler.cs new file mode 100644 index 000000000..785fae23f --- /dev/null +++ b/src/framework/Core/CQRS/ICommandHandler.cs @@ -0,0 +1,12 @@ +namespace FSH.Framework.Core.CQRS; + +/// +/// Handles a command and returns a result. +/// +/// Type of command +/// Type of response +public interface ICommandHandler + where TCommand : ICommand +{ + Task HandleAsync(TCommand command, CancellationToken cancellationToken = default); +} diff --git a/src/framework/Core/CQRS/IQuery.cs b/src/framework/Core/CQRS/IQuery.cs new file mode 100644 index 000000000..d28393382 --- /dev/null +++ b/src/framework/Core/CQRS/IQuery.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Core.CQRS; + +// Marker for query requests (intended to return data without modifying state) +public interface IQuery : IRequest { } diff --git a/src/framework/Core/CQRS/IQueryDispatcher.cs b/src/framework/Core/CQRS/IQueryDispatcher.cs new file mode 100644 index 000000000..4876f0e3a --- /dev/null +++ b/src/framework/Core/CQRS/IQueryDispatcher.cs @@ -0,0 +1,9 @@ +namespace FSH.Framework.Core.CQRS; +public interface IQueryDispatcher +{ + /// + /// Sends a query to its handler. + /// + Task SendAsync(TQuery query, CancellationToken ct = default) + where TQuery : IQuery; +} diff --git a/src/framework/Core/CQRS/IQueryHandler.cs b/src/framework/Core/CQRS/IQueryHandler.cs new file mode 100644 index 000000000..343f66262 --- /dev/null +++ b/src/framework/Core/CQRS/IQueryHandler.cs @@ -0,0 +1,12 @@ +namespace FSH.Framework.Core.CQRS; + +/// +/// Handles a query and returns a result. +/// +/// Type of query +/// Type of response +public interface IQueryHandler + where TQuery : IQuery +{ + Task HandleAsync(TQuery query, CancellationToken cancellationToken = default); +} diff --git a/src/framework/Core/CQRS/IRequest.cs b/src/framework/Core/CQRS/IRequest.cs new file mode 100644 index 000000000..8138364fa --- /dev/null +++ b/src/framework/Core/CQRS/IRequest.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Core.CQRS; + +// Represents a generic request with a response +public interface IRequest { } diff --git a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs index ec51a0b1c..faaad9f25 100644 --- a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs +++ b/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; +using FSH.Framework.Shared.Constants; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -21,7 +21,7 @@ public static AuthorizationBuilder AddRequiredPermissionPolicy(this Authorizatio builder.AddPolicy(RequiredPermissionDefaults.PolicyName, policy => { policy.RequireAuthenticatedUser(); - policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme); + policy.AddAuthenticationSchemes(AuthenticationConstants.AuthenticationScheme); policy.RequireRequiredPermissions(); }); diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index 3f2a5bb3f..e18eab01c 100644 --- a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -18,7 +18,6 @@ - diff --git a/src/framework/Infrastructure/CQRS/CommandDispatcher.cs b/src/framework/Infrastructure/CQRS/CommandDispatcher.cs new file mode 100644 index 000000000..1bc855ab5 --- /dev/null +++ b/src/framework/Infrastructure/CQRS/CommandDispatcher.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.CQRS; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Infrastructure.CQRS; +public class CommandDispatcher : ICommandDispatcher +{ + private readonly IServiceProvider _serviceProvider; + + public CommandDispatcher(IServiceProvider serviceProvider) => + _serviceProvider = serviceProvider; + + public Task SendAsync(TCommand command, CancellationToken ct = default) + where TCommand : ICommand + { + ArgumentNullException.ThrowIfNull(command); + + var handler = _serviceProvider.GetRequiredService>(); + return handler.HandleAsync(command, ct); + } +} diff --git a/src/framework/Infrastructure/CQRS/Extensions.cs b/src/framework/Infrastructure/CQRS/Extensions.cs new file mode 100644 index 000000000..2376b5381 --- /dev/null +++ b/src/framework/Infrastructure/CQRS/Extensions.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using FSH.Framework.Core.CQRS; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Infrastructure.CQRS; +public static class Extensions +{ + public static IServiceCollection RegisterCommandAndQueryHandlers(this IServiceCollection services, params Assembly[] assemblies) + { + // Register dispatchers + services.AddScoped(); + services.AddScoped(); + + // Scan for handlers in provided assemblies + services.Scan(scan => scan + .FromAssemblies(assemblies) + .AddClasses(c => c.AssignableTo(typeof(ICommandHandler<,>))) + .AsImplementedInterfaces() + .WithScopedLifetime()); + + services.Scan(scan => scan + .FromAssemblies(assemblies) + .AddClasses(c => c.AssignableTo(typeof(IQueryHandler<,>))) + .AsImplementedInterfaces() + .WithScopedLifetime()); + + return services; + } +} diff --git a/src/framework/Infrastructure/CQRS/QueryDispatcher.cs b/src/framework/Infrastructure/CQRS/QueryDispatcher.cs new file mode 100644 index 000000000..5a7e0b4a0 --- /dev/null +++ b/src/framework/Infrastructure/CQRS/QueryDispatcher.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.CQRS; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Infrastructure.CQRS; +public class QueryDispatcher : IQueryDispatcher +{ + private readonly IServiceProvider _serviceProvider; + + public QueryDispatcher(IServiceProvider serviceProvider) => + _serviceProvider = serviceProvider; + + public Task SendAsync(TQuery query, CancellationToken ct = default) + where TQuery : IQuery + { + ArgumentNullException.ThrowIfNull(query); + + var handler = _serviceProvider.GetRequiredService>(); + return handler.HandleAsync(query, ct); + } +} diff --git a/src/framework/Infrastructure/Infrastructure.csproj b/src/framework/Infrastructure/Infrastructure.csproj index 4a5210eff..33601f76b 100644 --- a/src/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Infrastructure/Infrastructure.csproj @@ -23,6 +23,7 @@ + diff --git a/src/framework/Shared/Constants/AuthenticationConstants.cs b/src/framework/Shared/Constants/AuthenticationConstants.cs new file mode 100644 index 000000000..3bb1edadc --- /dev/null +++ b/src/framework/Shared/Constants/AuthenticationConstants.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Shared.Constants; +public static class AuthenticationConstants +{ + public const string AuthenticationScheme = "Bearer"; +} diff --git a/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs b/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs new file mode 100644 index 000000000..dfae1c2d5 --- /dev/null +++ b/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs @@ -0,0 +1,20 @@ +namespace FSH.Framework.Tenant.Core.Abstractions; + +public interface ITenantService +{ + Task> GetAllAsync(); + + Task ExistsWithIdAsync(string id); + + Task ExistsWithNameAsync(string name); + + Task GetByIdAsync(string id); + + Task CreateAsync(CreateTenantCommand request, CancellationToken cancellationToken); + + Task ActivateAsync(string id, CancellationToken cancellationToken); + + Task DeactivateAsync(string id); + + Task UpgradeSubscription(string id, DateTime extendedExpiryDate); +} diff --git a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs new file mode 100644 index 000000000..b1d77790e --- /dev/null +++ b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs @@ -0,0 +1,4 @@ +using MediatR; + +namespace FSH.Framework.Tenant.Core.Features.Activate; +public record ActivateTenantCommand(string TenantId) : IRequest; diff --git a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj index 15d657734..13aa09383 100644 --- a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj +++ b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj @@ -8,6 +8,10 @@ enable enable + + + + diff --git a/src/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenantEndpoint.cs similarity index 79% rename from src/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs rename to src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenantEndpoint.cs index 4f2f24f87..0160b5690 100644 --- a/src/framework/Infrastructure/Tenant/Endpoints/ActivateTenantEndpoint.cs +++ b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenantEndpoint.cs @@ -1,11 +1,9 @@ -using FSH.Framework.Core.Tenant.Features.ActivateTenant; -using FSH.Framework.Infrastructure.Auth.Policy; -using MediatR; +using MediatR; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; +namespace FSH.Framework.Tenant.Endpoints.v1.Activate; public static class ActivateTenantEndpoint { internal static RouteHandlerBuilder MapActivateTenantEndpoint(this IEndpointRouteBuilder endpoints) diff --git a/src/framework/Infrastructure/Tenant/Endpoints/CreateTenantEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenantEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Tenant/Endpoints/CreateTenantEndpoint.cs rename to src/framework/Tenant/Tenant.Endpoints/v1/CreateTenantEndpoint.cs diff --git a/src/framework/Infrastructure/Tenant/Endpoints/DisableTenantEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenantEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Tenant/Endpoints/DisableTenantEndpoint.cs rename to src/framework/Tenant/Tenant.Endpoints/v1/DisableTenantEndpoint.cs diff --git a/src/framework/Infrastructure/Tenant/Endpoints/Extensions.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Extensions.cs similarity index 88% rename from src/framework/Infrastructure/Tenant/Endpoints/Extensions.cs rename to src/framework/Tenant/Tenant.Endpoints/v1/Extensions.cs index bc8851100..30a6c3b8b 100644 --- a/src/framework/Infrastructure/Tenant/Endpoints/Extensions.cs +++ b/src/framework/Tenant/Tenant.Endpoints/v1/Extensions.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Builder; +using FSH.Framework.Tenant.Endpoints.v1.Activate; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Infrastructure/Tenant/Endpoints/GetTenantByIdEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Tenant/Endpoints/GetTenantByIdEndpoint.cs rename to src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs diff --git a/src/framework/Infrastructure/Tenant/Endpoints/GetTenantsEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantsEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Tenant/Endpoints/GetTenantsEndpoint.cs rename to src/framework/Tenant/Tenant.Endpoints/v1/GetTenantsEndpoint.cs diff --git a/src/framework/Infrastructure/Tenant/Endpoints/UpgradeSubscriptionEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscriptionEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Tenant/Endpoints/UpgradeSubscriptionEndpoint.cs rename to src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscriptionEndpoint.cs diff --git a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs index d5c48d82f..e4106bd91 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs @@ -6,6 +6,7 @@ using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Infrastructure.Persistence.Services; using FSH.Framework.Shared.Constants; +using FSH.Framework.Tenant.Core.Abstractions; using FSH.Framework.Tenant.Infrastructure.Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; diff --git a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs index 9e087cf54..2c9024e08 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs @@ -5,6 +5,7 @@ using FSH.Framework.Core.Tenant.Abstractions; using FSH.Framework.Core.Tenant.Dtos; using FSH.Framework.Core.Tenant.Features.CreateTenant; +using FSH.Framework.Tenant.Core.Abstractions; using Mapster; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; From 5159f84af771e5d4371b4a2a39f6fde48b5a1200 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 13:44:26 +0530 Subject: [PATCH 10/54] add cleaner mediator handler and notifications --- src/framework/Core/Core.csproj | 3 ++ src/framework/Core/Domain/BaseEntity.cs | 2 +- .../Core/Domain/Contracts/IEntity.cs | 2 +- .../Core/Domain/Events/DomainEvent.cs | 7 --- .../Core/Domain/Events/IDomainEvent.cs | 4 -- .../Core/{ => Messaging}/CQRS/ICommand.cs | 2 +- .../CQRS/ICommandDispatcher.cs | 2 +- .../{ => Messaging}/CQRS/ICommandHandler.cs | 2 +- .../Core/{ => Messaging}/CQRS/IQuery.cs | 2 +- .../{ => Messaging}/CQRS/IQueryDispatcher.cs | 2 +- .../{ => Messaging}/CQRS/IQueryHandler.cs | 2 +- .../Core/{ => Messaging}/CQRS/IRequest.cs | 2 +- .../Core/Messaging/Events/DomainEvent.cs | 5 ++ .../Core/Messaging/Events/IDomainEvent.cs | 4 ++ .../Core/Messaging/Events/IEventBus.cs | 5 ++ .../Core/Messaging/Events/IEventHandler.cs | 5 ++ .../Core/Messaging/Events/INotification.cs | 4 ++ .../Core/Messaging/Events/Notification.cs | 5 ++ .../{ => Messaging}/CQRS/CommandDispatcher.cs | 4 +- .../{ => Messaging}/CQRS/Extensions.cs | 22 +++++++-- .../{ => Messaging}/CQRS/QueryDispatcher.cs | 4 +- .../CQRS/Validation/CommandValidation.cs | 24 ++++++++++ .../CQRS/Validation/QueryValidation.cs | 24 ++++++++++ .../CQRS/Validation/ValidationHelper.cs | 21 ++++++++ .../Messaging/Events/Extensions.cs | 20 ++++++++ .../Messaging/Events/InMemoryEventBus.cs | 48 +++++++++++++++++++ 26 files changed, 198 insertions(+), 29 deletions(-) delete mode 100644 src/framework/Core/Domain/Events/DomainEvent.cs delete mode 100644 src/framework/Core/Domain/Events/IDomainEvent.cs rename src/framework/Core/{ => Messaging}/CQRS/ICommand.cs (72%) rename src/framework/Core/{ => Messaging}/CQRS/ICommandDispatcher.cs (84%) rename src/framework/Core/{ => Messaging}/CQRS/ICommandHandler.cs (89%) rename src/framework/Core/{ => Messaging}/CQRS/IQuery.cs (74%) rename src/framework/Core/{ => Messaging}/CQRS/IQueryDispatcher.cs (83%) rename src/framework/Core/{ => Messaging}/CQRS/IQueryHandler.cs (88%) rename src/framework/Core/{ => Messaging}/CQRS/IRequest.cs (65%) create mode 100644 src/framework/Core/Messaging/Events/DomainEvent.cs create mode 100644 src/framework/Core/Messaging/Events/IDomainEvent.cs create mode 100644 src/framework/Core/Messaging/Events/IEventBus.cs create mode 100644 src/framework/Core/Messaging/Events/IEventHandler.cs create mode 100644 src/framework/Core/Messaging/Events/INotification.cs create mode 100644 src/framework/Core/Messaging/Events/Notification.cs rename src/framework/Infrastructure/{ => Messaging}/CQRS/CommandDispatcher.cs (86%) rename src/framework/Infrastructure/{ => Messaging}/CQRS/Extensions.cs (56%) rename src/framework/Infrastructure/{ => Messaging}/CQRS/QueryDispatcher.cs (86%) create mode 100644 src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs create mode 100644 src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs create mode 100644 src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs create mode 100644 src/framework/Infrastructure/Messaging/Events/Extensions.cs create mode 100644 src/framework/Infrastructure/Messaging/Events/InMemoryEventBus.cs diff --git a/src/framework/Core/Core.csproj b/src/framework/Core/Core.csproj index 0cbd9722c..2bd4670f5 100644 --- a/src/framework/Core/Core.csproj +++ b/src/framework/Core/Core.csproj @@ -9,4 +9,7 @@ + + + diff --git a/src/framework/Core/Domain/BaseEntity.cs b/src/framework/Core/Domain/BaseEntity.cs index 1c2e98daa..7b562d2f4 100644 --- a/src/framework/Core/Domain/BaseEntity.cs +++ b/src/framework/Core/Domain/BaseEntity.cs @@ -1,7 +1,7 @@ using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations.Schema; using FSH.Framework.Core.Domain.Contracts; -using FSH.Framework.Core.Domain.Events; +using FSH.Framework.Core.Messaging.Events; namespace FSH.Framework.Core.Domain; diff --git a/src/framework/Core/Domain/Contracts/IEntity.cs b/src/framework/Core/Domain/Contracts/IEntity.cs index 1d48d306d..f6e19a619 100644 --- a/src/framework/Core/Domain/Contracts/IEntity.cs +++ b/src/framework/Core/Domain/Contracts/IEntity.cs @@ -1,5 +1,5 @@ using System.Collections.ObjectModel; -using FSH.Framework.Core.Domain.Events; +using FSH.Framework.Core.Messaging.Events; namespace FSH.Framework.Core.Domain.Contracts; diff --git a/src/framework/Core/Domain/Events/DomainEvent.cs b/src/framework/Core/Domain/Events/DomainEvent.cs deleted file mode 100644 index 535085460..000000000 --- a/src/framework/Core/Domain/Events/DomainEvent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using MediatR; - -namespace FSH.Framework.Core.Domain.Events; -public abstract record DomainEvent : IDomainEvent, INotification -{ - public DateTime RaisedOn { get; protected set; } = DateTime.UtcNow; -} diff --git a/src/framework/Core/Domain/Events/IDomainEvent.cs b/src/framework/Core/Domain/Events/IDomainEvent.cs deleted file mode 100644 index 68d4c8f6c..000000000 --- a/src/framework/Core/Domain/Events/IDomainEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace FSH.Framework.Core.Domain.Events; -public interface IDomainEvent -{ -} diff --git a/src/framework/Core/CQRS/ICommand.cs b/src/framework/Core/Messaging/CQRS/ICommand.cs similarity index 72% rename from src/framework/Core/CQRS/ICommand.cs rename to src/framework/Core/Messaging/CQRS/ICommand.cs index 1f0baad0f..d6acb6af8 100644 --- a/src/framework/Core/CQRS/ICommand.cs +++ b/src/framework/Core/Messaging/CQRS/ICommand.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.CQRS; +namespace FSH.Framework.Core.Messaging.CQRS; // Marker for command requests (intended to modify system state) public interface ICommand : IRequest { } diff --git a/src/framework/Core/CQRS/ICommandDispatcher.cs b/src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs similarity index 84% rename from src/framework/Core/CQRS/ICommandDispatcher.cs rename to src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs index c308d2efc..aea040f7b 100644 --- a/src/framework/Core/CQRS/ICommandDispatcher.cs +++ b/src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.CQRS; +namespace FSH.Framework.Core.Messaging.CQRS; public interface ICommandDispatcher { /// diff --git a/src/framework/Core/CQRS/ICommandHandler.cs b/src/framework/Core/Messaging/CQRS/ICommandHandler.cs similarity index 89% rename from src/framework/Core/CQRS/ICommandHandler.cs rename to src/framework/Core/Messaging/CQRS/ICommandHandler.cs index 785fae23f..525b0319b 100644 --- a/src/framework/Core/CQRS/ICommandHandler.cs +++ b/src/framework/Core/Messaging/CQRS/ICommandHandler.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.CQRS; +namespace FSH.Framework.Core.Messaging.CQRS; /// /// Handles a command and returns a result. diff --git a/src/framework/Core/CQRS/IQuery.cs b/src/framework/Core/Messaging/CQRS/IQuery.cs similarity index 74% rename from src/framework/Core/CQRS/IQuery.cs rename to src/framework/Core/Messaging/CQRS/IQuery.cs index d28393382..254880121 100644 --- a/src/framework/Core/CQRS/IQuery.cs +++ b/src/framework/Core/Messaging/CQRS/IQuery.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.CQRS; +namespace FSH.Framework.Core.Messaging.CQRS; // Marker for query requests (intended to return data without modifying state) public interface IQuery : IRequest { } diff --git a/src/framework/Core/CQRS/IQueryDispatcher.cs b/src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs similarity index 83% rename from src/framework/Core/CQRS/IQueryDispatcher.cs rename to src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs index 4876f0e3a..2eb5d5ae3 100644 --- a/src/framework/Core/CQRS/IQueryDispatcher.cs +++ b/src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.CQRS; +namespace FSH.Framework.Core.Messaging.CQRS; public interface IQueryDispatcher { /// diff --git a/src/framework/Core/CQRS/IQueryHandler.cs b/src/framework/Core/Messaging/CQRS/IQueryHandler.cs similarity index 88% rename from src/framework/Core/CQRS/IQueryHandler.cs rename to src/framework/Core/Messaging/CQRS/IQueryHandler.cs index 343f66262..ba5f5c6d8 100644 --- a/src/framework/Core/CQRS/IQueryHandler.cs +++ b/src/framework/Core/Messaging/CQRS/IQueryHandler.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.CQRS; +namespace FSH.Framework.Core.Messaging.CQRS; /// /// Handles a query and returns a result. diff --git a/src/framework/Core/CQRS/IRequest.cs b/src/framework/Core/Messaging/CQRS/IRequest.cs similarity index 65% rename from src/framework/Core/CQRS/IRequest.cs rename to src/framework/Core/Messaging/CQRS/IRequest.cs index 8138364fa..0ddf2c223 100644 --- a/src/framework/Core/CQRS/IRequest.cs +++ b/src/framework/Core/Messaging/CQRS/IRequest.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.CQRS; +namespace FSH.Framework.Core.Messaging.CQRS; // Represents a generic request with a response public interface IRequest { } diff --git a/src/framework/Core/Messaging/Events/DomainEvent.cs b/src/framework/Core/Messaging/Events/DomainEvent.cs new file mode 100644 index 000000000..b3c721d34 --- /dev/null +++ b/src/framework/Core/Messaging/Events/DomainEvent.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Core.Messaging.Events; +public abstract record DomainEvent : IDomainEvent +{ + public DateTime RaisedOn { get; protected set; } = DateTime.UtcNow; +} diff --git a/src/framework/Core/Messaging/Events/IDomainEvent.cs b/src/framework/Core/Messaging/Events/IDomainEvent.cs new file mode 100644 index 000000000..2ff120db6 --- /dev/null +++ b/src/framework/Core/Messaging/Events/IDomainEvent.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Core.Messaging.Events; +public interface IDomainEvent +{ +} diff --git a/src/framework/Core/Messaging/Events/IEventBus.cs b/src/framework/Core/Messaging/Events/IEventBus.cs new file mode 100644 index 000000000..f0194e678 --- /dev/null +++ b/src/framework/Core/Messaging/Events/IEventBus.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Core.Messaging.Events; +public interface IEventBus +{ + Task PublishAsync(TEvent @event, CancellationToken cancellationToken = default); +} diff --git a/src/framework/Core/Messaging/Events/IEventHandler.cs b/src/framework/Core/Messaging/Events/IEventHandler.cs new file mode 100644 index 000000000..43e37ba3c --- /dev/null +++ b/src/framework/Core/Messaging/Events/IEventHandler.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Core.Messaging.Events; +public interface IEventHandler +{ + Task HandleAsync(TEvent @event, CancellationToken cancellationToken = default); +} diff --git a/src/framework/Core/Messaging/Events/INotification.cs b/src/framework/Core/Messaging/Events/INotification.cs new file mode 100644 index 000000000..c7b8f27dc --- /dev/null +++ b/src/framework/Core/Messaging/Events/INotification.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Core.Messaging.Events; +public interface INotification +{ +} diff --git a/src/framework/Core/Messaging/Events/Notification.cs b/src/framework/Core/Messaging/Events/Notification.cs new file mode 100644 index 000000000..8ed5c121b --- /dev/null +++ b/src/framework/Core/Messaging/Events/Notification.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Core.Messaging.Events; +public abstract record Notification : INotification +{ + public DateTime RaisedOn { get; protected set; } = DateTime.UtcNow; +} diff --git a/src/framework/Infrastructure/CQRS/CommandDispatcher.cs b/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs similarity index 86% rename from src/framework/Infrastructure/CQRS/CommandDispatcher.cs rename to src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs index 1bc855ab5..78a9b3285 100644 --- a/src/framework/Infrastructure/CQRS/CommandDispatcher.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs @@ -1,7 +1,7 @@ -using FSH.Framework.Core.CQRS; +using FSH.Framework.Core.Messaging.CQRS; using Microsoft.Extensions.DependencyInjection; -namespace FSH.Framework.Infrastructure.CQRS; +namespace FSH.Framework.Infrastructure.Messaging.CQRS; public class CommandDispatcher : ICommandDispatcher { private readonly IServiceProvider _serviceProvider; diff --git a/src/framework/Infrastructure/CQRS/Extensions.cs b/src/framework/Infrastructure/Messaging/CQRS/Extensions.cs similarity index 56% rename from src/framework/Infrastructure/CQRS/Extensions.cs rename to src/framework/Infrastructure/Messaging/CQRS/Extensions.cs index 2376b5381..f1779aef5 100644 --- a/src/framework/Infrastructure/CQRS/Extensions.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Extensions.cs @@ -1,25 +1,37 @@ using System.Reflection; -using FSH.Framework.Core.CQRS; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Infrastructure.Messaging.CQRS.Validation; using Microsoft.Extensions.DependencyInjection; -namespace FSH.Framework.Infrastructure.CQRS; +namespace FSH.Framework.Infrastructure.Messaging.CQRS; public static class Extensions { - public static IServiceCollection RegisterCommandAndQueryHandlers(this IServiceCollection services, params Assembly[] assemblies) + public static IServiceCollection RegisterCommandAndQueryDispatchers(this IServiceCollection services) { // Register dispatchers services.AddScoped(); services.AddScoped(); + // Register decorators + services.Decorate(); + services.Decorate(); + + return services; + } + public static IServiceCollection RegisterCommandAndQueryHandlers(this IServiceCollection services, params Assembly[] assemblies) + { + // Deduplicate Assemblies + var distinctAssemblies = assemblies.Distinct().ToArray(); + // Scan for handlers in provided assemblies services.Scan(scan => scan - .FromAssemblies(assemblies) + .FromAssemblies(distinctAssemblies) .AddClasses(c => c.AssignableTo(typeof(ICommandHandler<,>))) .AsImplementedInterfaces() .WithScopedLifetime()); services.Scan(scan => scan - .FromAssemblies(assemblies) + .FromAssemblies(distinctAssemblies) .AddClasses(c => c.AssignableTo(typeof(IQueryHandler<,>))) .AsImplementedInterfaces() .WithScopedLifetime()); diff --git a/src/framework/Infrastructure/CQRS/QueryDispatcher.cs b/src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs similarity index 86% rename from src/framework/Infrastructure/CQRS/QueryDispatcher.cs rename to src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs index 5a7e0b4a0..36c240eb7 100644 --- a/src/framework/Infrastructure/CQRS/QueryDispatcher.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs @@ -1,7 +1,7 @@ -using FSH.Framework.Core.CQRS; +using FSH.Framework.Core.Messaging.CQRS; using Microsoft.Extensions.DependencyInjection; -namespace FSH.Framework.Infrastructure.CQRS; +namespace FSH.Framework.Infrastructure.Messaging.CQRS; public class QueryDispatcher : IQueryDispatcher { private readonly IServiceProvider _serviceProvider; diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs new file mode 100644 index 000000000..a24ac3a64 --- /dev/null +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs @@ -0,0 +1,24 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; +public class CommandValidation : ICommandDispatcher +{ + private readonly ICommandDispatcher _inner; + private readonly IEnumerable> _validators; + + public CommandValidation(ICommandDispatcher inner, IEnumerable> validators) + { + _inner = inner; + _validators = validators; + } + + public async Task SendAsync(TCommand command, CancellationToken ct = default) + where TCommand : ICommand + { + var typedValidators = _validators.OfType>(); + await ValidationHelper.ValidateAsync(command, typedValidators, ct); + + return await _inner.SendAsync(command, ct); + } +} diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs new file mode 100644 index 000000000..4f69ac2d0 --- /dev/null +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs @@ -0,0 +1,24 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; +internal class QueryValidation : IQueryDispatcher +{ + private readonly IQueryDispatcher _inner; + private readonly IEnumerable> _validators; + + public QueryValidation(IQueryDispatcher inner, IEnumerable> validators) + { + _inner = inner; + _validators = validators; + } + + public async Task SendAsync(TQuery query, CancellationToken ct = default) + where TQuery : IQuery + { + var typedValidators = _validators.OfType>(); + await ValidationHelper.ValidateAsync(query, typedValidators, ct); + + return await _inner.SendAsync(query, ct); + } +} diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs new file mode 100644 index 000000000..9a8bd4c3f --- /dev/null +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs @@ -0,0 +1,21 @@ +using FluentValidation; + +namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; + +internal static class ValidationHelper +{ + public static async Task ValidateAsync( + TRequest request, + IEnumerable> validators, + CancellationToken cancellationToken) + { + if (!validators.Any()) return; + + var context = new ValidationContext(request); + var results = await Task.WhenAll(validators.Select(v => v.ValidateAsync(context, cancellationToken))); + var failures = results.SelectMany(r => r.Errors).Where(f => f != null).ToList(); + + if (failures.Count > 0) + throw new ValidationException(failures); + } +} diff --git a/src/framework/Infrastructure/Messaging/Events/Extensions.cs b/src/framework/Infrastructure/Messaging/Events/Extensions.cs new file mode 100644 index 000000000..e219fd824 --- /dev/null +++ b/src/framework/Infrastructure/Messaging/Events/Extensions.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using FSH.Framework.Core.Messaging.Events; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Infrastructure.Messaging.Events; +public static class Extensions +{ + public static IServiceCollection RegisterInMemoryEventBus(this IServiceCollection services, params Assembly[] assemblies) + { + services.AddScoped(); + + services.Scan(scan => scan + .FromAssemblies(assemblies) + .AddClasses(c => c.AssignableTo(typeof(IEventHandler<>))) + .AsImplementedInterfaces() + .WithScopedLifetime()); + + return services; + } +} diff --git a/src/framework/Infrastructure/Messaging/Events/InMemoryEventBus.cs b/src/framework/Infrastructure/Messaging/Events/InMemoryEventBus.cs new file mode 100644 index 000000000..dcfb0941a --- /dev/null +++ b/src/framework/Infrastructure/Messaging/Events/InMemoryEventBus.cs @@ -0,0 +1,48 @@ +using FSH.Framework.Core.Messaging.Events; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Infrastructure.Messaging.Events; + +public class InMemoryEventBus : IEventBus +{ + private readonly IServiceProvider _serviceProvider; + + public InMemoryEventBus(IServiceProvider serviceProvider) => + _serviceProvider = serviceProvider; + + public async Task PublishAsync(TEvent @event, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(@event); + + using var scope = _serviceProvider.CreateScope(); + var handlers = scope.ServiceProvider.GetServices>(); + + foreach (var handler in handlers) + { + const int maxAttempts = 3; + int attempt = 0; + + while (attempt < maxAttempts) + { + try + { + attempt++; + await handler.HandleAsync(@event, cancellationToken); + break; // Success + } + catch (Exception ex) + { + if (attempt == maxAttempts) + { + Console.WriteLine($"❌ Handler for {typeof(TEvent).Name} failed after {attempt} attempts: {ex.Message}"); + // Optionally: Add to dead-letter queue + } + else + { + await Task.Delay(100 * attempt, cancellationToken); // simple backoff + } + } + } + } + } +} From fc61c98bceece8a7a680f3bc09a7d2fa9b41c136 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 14:19:00 +0530 Subject: [PATCH 11/54] cleanup --- .../Auditing.Core/Auditing.Core.csproj | 4 ++- .../Events/AuditPublishedEvent.cs | 2 +- .../Auditing.Endpoints.csproj | 1 + .../Auditing.Endpoints/AuditingModule.cs | 27 +++++++++++++++++++ .../{IEventBus.cs => IEventPublisher.cs} | 2 +- .../ActivateTenant/ActivateTenantCommand.cs | 4 --- .../ActivateTenant/ActivateTenantResponse.cs | 2 -- .../Messaging/Events/Extensions.cs | 2 +- ...yEventBus.cs => InMemoryEventPublisher.cs} | 6 ++--- .../Persistence/FshDbContext.cs | 15 ++++++----- .../Multitenancy}/FshTenantInfo.cs | 6 ++--- .../Multitenancy}/IFshTenantInfo.cs | 2 +- src/framework/Shared/Shared.csproj | 3 +++ .../Activate/ActivateTenantCommand.cs | 4 +-- .../Activate/ActivateTenantResponse.cs | 2 ++ .../Tenant/Tenant.Core/Tenant.Core.csproj | 3 +++ .../Data/TenantDbContext.cs | 1 + .../Tenant.Infrastructure/Extensions.cs | 1 + .../Tenant.Infrastructure/TenantService.cs | 1 + 19 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs rename src/framework/Core/Messaging/Events/{IEventBus.cs => IEventPublisher.cs} (81%) delete mode 100644 src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs delete mode 100644 src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs rename src/framework/Infrastructure/Messaging/Events/{InMemoryEventBus.cs => InMemoryEventPublisher.cs} (84%) rename src/framework/{Tenant/Tenant.Infrastructure => Shared/Multitenancy}/FshTenantInfo.cs (91%) rename src/framework/{Tenant/Tenant.Core/Abstractions => Shared/Multitenancy}/IFshTenantInfo.cs (59%) create mode 100644 src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs diff --git a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj index 8bb8eb1ed..62146b41a 100644 --- a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj +++ b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj @@ -9,8 +9,10 @@ enable - + + + diff --git a/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs b/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs index 969e1f524..848f260a9 100644 --- a/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs +++ b/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs @@ -1,5 +1,5 @@ using FSH.Framework.Auditing.Core.Dtos; -using MediatR; +using FSH.Framework.Core.Messaging.Events; namespace FSH.Framework.Auditing.Core.Events; diff --git a/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj b/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj index 218a24767..aaaf8dbb5 100644 --- a/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj +++ b/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj @@ -13,6 +13,7 @@ + diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs new file mode 100644 index 000000000..e8b622431 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using FSH.Framework.Auditing.Endpoints.v1.GetUserAudits; +using FSH.Framework.Infrastructure.Messaging.CQRS; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Auditing.Endpoints; + +public static class AuditingModule +{ + public static IServiceCollection AddAuditingModule(this IServiceCollection services) + { + services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); + + // Add infrastructure, services, mappings, etc. + + return services; + } + + public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuilder endpoints) + { + // v1 endpoints + endpoints.MapGetUserAuditTrailEndpoint(); + + return endpoints; + } +} diff --git a/src/framework/Core/Messaging/Events/IEventBus.cs b/src/framework/Core/Messaging/Events/IEventPublisher.cs similarity index 81% rename from src/framework/Core/Messaging/Events/IEventBus.cs rename to src/framework/Core/Messaging/Events/IEventPublisher.cs index f0194e678..d56b696ac 100644 --- a/src/framework/Core/Messaging/Events/IEventBus.cs +++ b/src/framework/Core/Messaging/Events/IEventPublisher.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Core.Messaging.Events; -public interface IEventBus +public interface IEventPublisher { Task PublishAsync(TEvent @event, CancellationToken cancellationToken = default); } diff --git a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs deleted file mode 100644 index 01f902dfc..000000000 --- a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantCommand.cs +++ /dev/null @@ -1,4 +0,0 @@ -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.ActivateTenant; -public record ActivateTenantCommand(string TenantId) : IRequest; diff --git a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs deleted file mode 100644 index bd396891d..000000000 --- a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantResponse.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Core.Tenant.Features.ActivateTenant; -public record ActivateTenantResponse(string Status); diff --git a/src/framework/Infrastructure/Messaging/Events/Extensions.cs b/src/framework/Infrastructure/Messaging/Events/Extensions.cs index e219fd824..9f2584951 100644 --- a/src/framework/Infrastructure/Messaging/Events/Extensions.cs +++ b/src/framework/Infrastructure/Messaging/Events/Extensions.cs @@ -7,7 +7,7 @@ public static class Extensions { public static IServiceCollection RegisterInMemoryEventBus(this IServiceCollection services, params Assembly[] assemblies) { - services.AddScoped(); + services.AddScoped(); services.Scan(scan => scan .FromAssemblies(assemblies) diff --git a/src/framework/Infrastructure/Messaging/Events/InMemoryEventBus.cs b/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs similarity index 84% rename from src/framework/Infrastructure/Messaging/Events/InMemoryEventBus.cs rename to src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs index dcfb0941a..4fc0bcbed 100644 --- a/src/framework/Infrastructure/Messaging/Events/InMemoryEventBus.cs +++ b/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs @@ -3,11 +3,11 @@ namespace FSH.Framework.Infrastructure.Messaging.Events; -public class InMemoryEventBus : IEventBus +public class InMemoryEventPublisher : IEventPublisher { private readonly IServiceProvider _serviceProvider; - public InMemoryEventBus(IServiceProvider serviceProvider) => + public InMemoryEventPublisher(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; public async Task PublishAsync(TEvent @event, CancellationToken cancellationToken = default) @@ -34,7 +34,7 @@ public async Task PublishAsync(TEvent @event, CancellationToken cancella { if (attempt == maxAttempts) { - Console.WriteLine($"❌ Handler for {typeof(TEvent).Name} failed after {attempt} attempts: {ex.Message}"); + Console.WriteLine($"Handler for {typeof(TEvent).Name} failed after {attempt} attempts: {ex.Message}"); // Optionally: Add to dead-letter queue } else diff --git a/src/framework/Infrastructure/Persistence/FshDbContext.cs b/src/framework/Infrastructure/Persistence/FshDbContext.cs index 1f3186e3e..8ed626083 100644 --- a/src/framework/Infrastructure/Persistence/FshDbContext.cs +++ b/src/framework/Infrastructure/Persistence/FshDbContext.cs @@ -1,20 +1,19 @@ using Finbuckle.MultiTenant.Abstractions; using Finbuckle.MultiTenant.EntityFrameworkCore; using FSH.Framework.Core.Domain.Contracts; +using FSH.Framework.Core.Messaging.Events; using FSH.Framework.Core.Persistence; -using FSH.Framework.Infrastructure.Tenant; -using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; namespace FSH.Framework.Infrastructure.Persistence; public class FshDbContext(IMultiTenantContextAccessor multiTenantContextAccessor, DbContextOptions options, - IPublisher publisher, + IEventPublisher publisher, IOptions settings) : MultiTenantDbContext(multiTenantContextAccessor, options) { - private readonly IPublisher _publisher = publisher; + private readonly IEventPublisher _publisher = publisher; private readonly DatabaseOptions _settings = settings.Value; protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -36,10 +35,12 @@ public override async Task SaveChangesAsync(CancellationToken cancellationT { this.TenantNotSetMode = TenantNotSetMode.Overwrite; int result = await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false); - await PublishDomainEventsAsync().ConfigureAwait(false); + await PublishDomainEventsAsync(cancellationToken).ConfigureAwait(false); return result; } - private async Task PublishDomainEventsAsync() + + // todo: move this to interceptor + private async Task PublishDomainEventsAsync(CancellationToken cancellationToken = default) { var domainEvents = ChangeTracker.Entries() .Select(e => e.Entity) @@ -54,7 +55,7 @@ private async Task PublishDomainEventsAsync() foreach (var domainEvent in domainEvents) { - await _publisher.Publish(domainEvent).ConfigureAwait(false); + await _publisher.PublishAsync(domainEvent, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/framework/Tenant/Tenant.Infrastructure/FshTenantInfo.cs b/src/framework/Shared/Multitenancy/FshTenantInfo.cs similarity index 91% rename from src/framework/Tenant/Tenant.Infrastructure/FshTenantInfo.cs rename to src/framework/Shared/Multitenancy/FshTenantInfo.cs index e102b040e..d4cb1c14f 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/FshTenantInfo.cs +++ b/src/framework/Shared/Multitenancy/FshTenantInfo.cs @@ -1,9 +1,7 @@ using Finbuckle.MultiTenant.Abstractions; -using FSH.Framework.Core.Exceptions; using FSH.Framework.Shared.Constants; -using FSH.Framework.Tenant.Core.Abstractions; -namespace FSH.Framework.Tenant.Infrastructure; +namespace FSH.Framework.Shared.Multitenancy; public class FshTenantInfo : ITenantInfo, IFshTenantInfo { public FshTenantInfo() @@ -40,7 +38,7 @@ public void AddValidity(int months) => public void SetValidity(in DateTime validTill) => ValidUpto = ValidUpto < validTill ? validTill - : throw new CustomException("Subscription cannot be backdated."); + : throw new InvalidOperationException("Subscription cannot be backdated."); public void Activate() { diff --git a/src/framework/Tenant/Tenant.Core/Abstractions/IFshTenantInfo.cs b/src/framework/Shared/Multitenancy/IFshTenantInfo.cs similarity index 59% rename from src/framework/Tenant/Tenant.Core/Abstractions/IFshTenantInfo.cs rename to src/framework/Shared/Multitenancy/IFshTenantInfo.cs index d2a7cdad3..2f8becc0c 100644 --- a/src/framework/Tenant/Tenant.Core/Abstractions/IFshTenantInfo.cs +++ b/src/framework/Shared/Multitenancy/IFshTenantInfo.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Tenant.Core.Abstractions; +namespace FSH.Framework.Shared.Multitenancy; public interface IFshTenantInfo { string? ConnectionString { get; set; } diff --git a/src/framework/Shared/Shared.csproj b/src/framework/Shared/Shared.csproj index 10e90edc9..e94022f4f 100644 --- a/src/framework/Shared/Shared.csproj +++ b/src/framework/Shared/Shared.csproj @@ -11,4 +11,7 @@ + + + diff --git a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs index b1d77790e..daaa872cb 100644 --- a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs +++ b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs @@ -1,4 +1,4 @@ -using MediatR; +using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Core.Features.Activate; -public record ActivateTenantCommand(string TenantId) : IRequest; +public record ActivateTenantCommand(string TenantId) : ICommand; diff --git a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs new file mode 100644 index 000000000..c89a2bcb3 --- /dev/null +++ b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Tenant.Core.Features.Activate; +public record ActivateTenantResponse(string Status); diff --git a/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj b/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj index 1feb07015..e1aee7da2 100644 --- a/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj +++ b/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj @@ -8,5 +8,8 @@ enable enable + + + diff --git a/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs b/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs index c350ddb85..de189da45 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs @@ -1,4 +1,5 @@ using Finbuckle.MultiTenant.EntityFrameworkCore.Stores.EFCoreStore; +using FSH.Framework.Shared.Multitenancy; using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Tenant.Infrastructure.Data; diff --git a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs index e4106bd91..6963932c7 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs @@ -6,6 +6,7 @@ using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Infrastructure.Persistence.Services; using FSH.Framework.Shared.Constants; +using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Core.Abstractions; using FSH.Framework.Tenant.Infrastructure.Data; using Microsoft.AspNetCore.Builder; diff --git a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs index 2c9024e08..b34498367 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs @@ -5,6 +5,7 @@ using FSH.Framework.Core.Tenant.Abstractions; using FSH.Framework.Core.Tenant.Dtos; using FSH.Framework.Core.Tenant.Features.CreateTenant; +using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Core.Abstractions; using Mapster; using Microsoft.Extensions.DependencyInjection; From f5b4aa910293836dfc8d9b5c157c3f3f4d8ccbe1 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 15:10:54 +0530 Subject: [PATCH 12/54] better cqrs handling --- .../Auditing.Endpoints/AuditingModule.cs | 2 +- .../Auditing.Endpoints/v1/GetUserAudits.cs | 46 +++++++++++++++++++ .../GetUserAuditTrailEndpoint.cs | 22 --------- src/framework/FSH.Framework.sln | 8 ++++ 4 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits/GetUserAuditTrailEndpoint.cs diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs index e8b622431..ac6165820 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -20,7 +20,7 @@ public static IServiceCollection AddAuditingModule(this IServiceCollection servi public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuilder endpoints) { // v1 endpoints - endpoints.MapGetUserAuditTrailEndpoint(); + endpoints.MapGetUserAuditsEndpoint(); return endpoints; } diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits.cs new file mode 100644 index 000000000..73abb049c --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits.cs @@ -0,0 +1,46 @@ +using FluentValidation; +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Auditing.Endpoints.v1; + +public static class GetUserAudits +{ + public sealed record Query(Guid UserId) : IQuery; + public sealed record Response(IReadOnlyList AuditTrails); + public sealed class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.UserId).NotEmpty(); + } + } + public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/auditing/users/{userId:guid}/trails", async ( + Guid id, + IQueryDispatcher dispatcher, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync(new Query(id), cancellationToken); + return TypedResults.Ok(result); + }) + .WithName(nameof(GetUserAudits)) + .WithSummary("Get user's audit trail details") + .RequirePermission("Permissions.AuditTrails.View") + .WithDescription("Get user's audit trail details."); + } + public sealed class Handler(IAuditService auditService) : IQueryHandler + { + public async Task HandleAsync(Query request, CancellationToken cancellationToken = default) + { + var trails = await auditService.GetUserTrailsAsync(request.UserId); + return new Response(trails); + } + } +} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits/GetUserAuditTrailEndpoint.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits/GetUserAuditTrailEndpoint.cs deleted file mode 100644 index 59b1724c0..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits/GetUserAuditTrailEndpoint.cs +++ /dev/null @@ -1,22 +0,0 @@ -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Shared.Authorization; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserAudits; - -public static class GetUserAuditTrailEndpoint -{ - internal static RouteHandlerBuilder MapGetUserAuditTrailEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/{id:guid}/audit-trails", (Guid id, IAuditService service) => - { - return service.GetUserTrailsAsync(id); - }) - .WithName(nameof(GetUserAuditTrailEndpoint)) - .WithSummary("Get user's audit trail details") - .RequirePermission("Permissions.AuditTrails.View") - .WithDescription("Get user's audit trail details."); - } -} diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 51e0e2a5d..ac7d5fa38 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Endpoints", "Tenant\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Infrastructure", "Tenant\Tenant.Infrastructure\Tenant.Infrastructure.csproj", "{F8AE32F3-31B9-4962-BE7A-1326BD13B739}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,9 +100,12 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {15EA2212-0958-4415-AA37-116F2A47F23F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {24E922E3-8C91-43A1-A110-D8F5276566BA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {D59824CA-B55C-4D45-B485-771B31FE7575} = {15EA2212-0958-4415-AA37-116F2A47F23F} {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC} = {15EA2212-0958-4415-AA37-116F2A47F23F} {CE91E947-D5FA-499A-BB28-373CB8209813} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {E5141F38-2D08-44DA-9A6C-B96890515168} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2} = {E5141F38-2D08-44DA-9A6C-B96890515168} {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786} = {E5141F38-2D08-44DA-9A6C-B96890515168} {C8DCA061-E4D6-414F-9053-0723B6764D71} = {E5141F38-2D08-44DA-9A6C-B96890515168} @@ -108,4 +113,7 @@ Global {86BC889E-322A-460E-81B6-601EE65B37C1} = {24E922E3-8C91-43A1-A110-D8F5276566BA} {F8AE32F3-31B9-4962-BE7A-1326BD13B739} = {24E922E3-8C91-43A1-A110-D8F5276566BA} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} + EndGlobalSection EndGlobal From b74d244789692f79ac2ddd5896e5131bf47229b7 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 15:44:37 +0530 Subject: [PATCH 13/54] cleanup --- .../Auditing.Endpoints/AuditingModule.cs | 19 +++++++++++++-- .../Auditing.Infrastructure.csproj | 4 +++- .../AuditingConstants.cs | 5 ++++ .../Data/AuditingConfiguration.cs | 17 ++++++++++++++ .../Tenant/Abstractions/ITenantService.cs | 23 ------------------- .../Data/IdentityConfigurations.cs | 16 ++----------- .../Data/IdentityDbContext.cs | 1 + .../Data/IdentityDbInitializer.cs | 1 + .../Identity.Infrastructure.csproj | 4 ---- .../IdentityConstants.cs | 5 ++++ 10 files changed, 51 insertions(+), 44 deletions(-) create mode 100644 src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs create mode 100644 src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs delete mode 100644 src/framework/Core/Tenant/Abstractions/ITenantService.cs create mode 100644 src/framework/Identity/Identity.Infrastructure/IdentityConstants.cs diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs index ac6165820..69e95d339 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -1,6 +1,10 @@ using System.Reflection; -using FSH.Framework.Auditing.Endpoints.v1.GetUserAudits; +using Asp.Versioning; +using Asp.Versioning.Builder; +using FSH.Framework.Auditing.Endpoints.v1; using FSH.Framework.Infrastructure.Messaging.CQRS; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; @@ -19,8 +23,19 @@ public static IServiceCollection AddAuditingModule(this IServiceCollection servi public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuilder endpoints) { + ApiVersionSet apiVersionSet = endpoints.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1)) + .ReportApiVersions() + .Build(); + + RouteGroupBuilder group = endpoints + .MapGroup("api/v{version:apiVersion}/auditing") + .WithTags("Auditing") + .WithOpenApi() + .WithApiVersionSet(apiVersionSet); + // v1 endpoints - endpoints.MapGetUserAuditsEndpoint(); + GetUserAudits.MapEndpoint(group); return endpoints; } diff --git a/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj b/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj index d29c813a4..bcbddd273 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj +++ b/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj @@ -12,5 +12,7 @@ - + + + diff --git a/src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs b/src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs new file mode 100644 index 000000000..be53107d2 --- /dev/null +++ b/src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Auditing.Infrastructure; +public static class AuditingConstants +{ + public const string SchemaName = "auditing"; +} diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs new file mode 100644 index 000000000..1dad50c33 --- /dev/null +++ b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs @@ -0,0 +1,17 @@ +using Finbuckle.MultiTenant; +using FSH.Framework.Auditing.Core.Dtos; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace FSH.Framework.Auditing.Infrastructure.Data; +public class AuditTrailConfig : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder + .ToTable("AuditTrails", AuditingConstants.SchemaName) + .IsMultiTenant(); + + builder.HasKey(a => a.Id); + } +} diff --git a/src/framework/Core/Tenant/Abstractions/ITenantService.cs b/src/framework/Core/Tenant/Abstractions/ITenantService.cs deleted file mode 100644 index d2540a2ff..000000000 --- a/src/framework/Core/Tenant/Abstractions/ITenantService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using FSH.Framework.Core.Tenant.Dtos; -using FSH.Framework.Core.Tenant.Features.CreateTenant; - -namespace FSH.Framework.Core.Tenant.Abstractions; - -public interface ITenantService -{ - Task> GetAllAsync(); - - Task ExistsWithIdAsync(string id); - - Task ExistsWithNameAsync(string name); - - Task GetByIdAsync(string id); - - Task CreateAsync(CreateTenantCommand request, CancellationToken cancellationToken); - - Task ActivateAsync(string id, CancellationToken cancellationToken); - - Task DeactivateAsync(string id); - - Task UpgradeSubscription(string id, DateTime extendedExpiryDate); -} diff --git a/src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs b/src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs index 83e2c4c38..6116fb99f 100644 --- a/src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs +++ b/src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs @@ -1,23 +1,11 @@ -using FSH.Framework.Auditing.Core.Dtos; +using Finbuckle.MultiTenant; +using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; -using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace FSH.Framework.Identity.Infrastructure.Data; -public class AuditTrailConfig : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder - .ToTable("AuditTrails", IdentityConstants.SchemaName) - .IsMultiTenant(); - - builder.HasKey(a => a.Id); - } -} - public class ApplicationUserConfig : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) diff --git a/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs index 4ba21bfaf..c97dc6646 100644 --- a/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs +++ b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs @@ -3,6 +3,7 @@ using FSH.Framework.Core.Persistence; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; diff --git a/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs index 0369630fb..0f6478afa 100644 --- a/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs +++ b/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs @@ -4,6 +4,7 @@ using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; using FSH.Framework.Shared.Constants; +using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index e18eab01c..31c1f1831 100644 --- a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -9,7 +9,6 @@ enable - @@ -18,9 +17,6 @@ - - - diff --git a/src/framework/Identity/Identity.Infrastructure/IdentityConstants.cs b/src/framework/Identity/Identity.Infrastructure/IdentityConstants.cs new file mode 100644 index 000000000..4542975e2 --- /dev/null +++ b/src/framework/Identity/Identity.Infrastructure/IdentityConstants.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Identity.Infrastructure; +public static class IdentityConstants +{ + public const string SchemaName = "identity"; +} From 1dd677827a6f94923d9deb5b76fdf18d7ba2d29a Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 15:50:45 +0530 Subject: [PATCH 14/54] cleanup audits --- .../Auditing.Core/Abstractions/IAuditService.cs | 2 +- .../Abstractions/IAuditingDbContext.cs | 2 +- .../Auditing.Core/Dtos/{AuditTrail.cs => Trail.cs} | 2 +- .../Auditing.Core/Events/AuditPublishedEvent.cs | 4 ++-- .../Auditing/Auditing.Endpoints/AuditingModule.cs | 2 +- .../v1/{GetUserAudits.cs => GetUserTrails.cs} | 8 ++++---- .../Data/AuditingConfiguration.cs | 6 +++--- .../Data/AuditingDbContext.cs | 2 +- .../Handlers/AuditPublishedEventHandler.cs | 2 +- .../Interceptors/AuditInterceptor.cs | 14 +++++++------- .../Services/AuditService.cs | 4 ++-- 11 files changed, 24 insertions(+), 24 deletions(-) rename src/framework/Auditing/Auditing.Core/Dtos/{AuditTrail.cs => Trail.cs} (98%) rename src/framework/Auditing/Auditing.Endpoints/v1/{GetUserAudits.cs => GetUserTrails.cs} (86%) diff --git a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs index 07857b7eb..57363c791 100644 --- a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs +++ b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs @@ -3,5 +3,5 @@ namespace FSH.Framework.Auditing.Core.Abstractions; public interface IAuditService { - Task> GetUserTrailsAsync(Guid userId); + Task> GetUserTrailsAsync(Guid userId); } diff --git a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs index 6744f15e1..d7698669f 100644 --- a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs +++ b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs @@ -4,6 +4,6 @@ namespace FSH.Framework.Auditing.Core.Abstractions; public interface IAuditingDbContext { - DbSet AuditTrails { get; } + DbSet Trails { get; } Task SaveChangesAsync(CancellationToken cancellationToken); } diff --git a/src/framework/Auditing/Auditing.Core/Dtos/AuditTrail.cs b/src/framework/Auditing/Auditing.Core/Dtos/Trail.cs similarity index 98% rename from src/framework/Auditing/Auditing.Core/Dtos/AuditTrail.cs rename to src/framework/Auditing/Auditing.Core/Dtos/Trail.cs index 73ba62c3a..3a8752114 100644 --- a/src/framework/Auditing/Auditing.Core/Dtos/AuditTrail.cs +++ b/src/framework/Auditing/Auditing.Core/Dtos/Trail.cs @@ -5,7 +5,7 @@ namespace FSH.Framework.Auditing.Core.Dtos; -public class AuditTrail +public class Trail { public Guid Id { get; set; } public Guid UserId { get; set; } diff --git a/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs b/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs index 848f260a9..d086a582a 100644 --- a/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs +++ b/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs @@ -5,9 +5,9 @@ namespace FSH.Framework.Auditing.Core.Events; public class AuditPublishedEvent : INotification { - public IReadOnlyCollection Trails { get; } + public IReadOnlyCollection Trails { get; } - public AuditPublishedEvent(IReadOnlyCollection trails) + public AuditPublishedEvent(IReadOnlyCollection trails) { Trails = trails; } diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs index 69e95d339..c95f7f985 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -35,7 +35,7 @@ public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuil .WithApiVersionSet(apiVersionSet); // v1 endpoints - GetUserAudits.MapEndpoint(group); + GetUserTrails.MapEndpoint(group); return endpoints; } diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs similarity index 86% rename from src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits.cs rename to src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs index 73abb049c..7518a5ada 100644 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserAudits.cs +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs @@ -9,10 +9,10 @@ namespace FSH.Framework.Auditing.Endpoints.v1; -public static class GetUserAudits +public static class GetUserTrails { public sealed record Query(Guid UserId) : IQuery; - public sealed record Response(IReadOnlyList AuditTrails); + public sealed record Response(IReadOnlyList AuditTrails); public sealed class Validator : AbstractValidator { public Validator() @@ -22,7 +22,7 @@ public Validator() } public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder endpoints) { - return endpoints.MapGet("/auditing/users/{userId:guid}/trails", async ( + return endpoints.MapGet("/users/{userId:guid}/trails", async ( Guid id, IQueryDispatcher dispatcher, CancellationToken cancellationToken) => @@ -30,7 +30,7 @@ public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder endpoints) var result = await dispatcher.SendAsync(new Query(id), cancellationToken); return TypedResults.Ok(result); }) - .WithName(nameof(GetUserAudits)) + .WithName(nameof(GetUserTrails)) .WithSummary("Get user's audit trail details") .RequirePermission("Permissions.AuditTrails.View") .WithDescription("Get user's audit trail details."); diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs index 1dad50c33..6824a041d 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs @@ -4,12 +4,12 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace FSH.Framework.Auditing.Infrastructure.Data; -public class AuditTrailConfig : IEntityTypeConfiguration +public class TrailConfig : IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public void Configure(EntityTypeBuilder builder) { builder - .ToTable("AuditTrails", AuditingConstants.SchemaName) + .ToTable("Trails", AuditingConstants.SchemaName) .IsMultiTenant(); builder.HasKey(a => a.Id); diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs index 68080b2a9..fd13f657a 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs @@ -5,7 +5,7 @@ namespace FSH.Framework.Auditing.Infrastructure.Data; public class AuditingDbContext : DbContext, IAuditingDbContext { - public DbSet AuditTrails { get; set; } + public DbSet Trails { get; set; } public AuditingDbContext(DbContextOptions options) : base(options) { } diff --git a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs index 971fa98c1..6f6525489 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs @@ -21,7 +21,7 @@ public async Task Handle(AuditPublishedEvent notification, CancellationToken can try { - await context.AuditTrails.AddRangeAsync(notification.Trails, cancellationToken); + await context.Trails.AddRangeAsync(notification.Trails, cancellationToken); await context.SaveChangesAsync(cancellationToken); logger.LogInformation("Persisted {Count} audit trail(s).", notification.Trails.Count); } diff --git a/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs b/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs index 886d59484..9f5dd80ba 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs @@ -4,13 +4,13 @@ using FSH.Framework.Core.Domain; using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.ExecutionContext; -using MediatR; +using FSH.Framework.Core.Messaging.Events; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; namespace FSH.Framework.Auditing.Infrastructure.Interceptors; -public class AuditInterceptor(ICurrentUser currentUser, TimeProvider timeProvider, IPublisher publisher) : SaveChangesInterceptor +public class AuditInterceptor(ICurrentUser currentUser, TimeProvider timeProvider, IEventPublisher publisher) : SaveChangesInterceptor { public override ValueTask SavedChangesAsync(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = default) { @@ -25,20 +25,20 @@ public override Task SaveChangesFailedAsync(DbContextErrorEventData eventData, C public override async ValueTask> SavingChangesAsync(DbContextEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) { UpdateEntities(eventData.Context); - await PublishAuditTrailsAsync(eventData); + await PublishAuditTrailsAsync(eventData, cancellationToken); return await base.SavingChangesAsync(eventData, result, cancellationToken); } - private async Task PublishAuditTrailsAsync(DbContextEventData eventData) + private async Task PublishAuditTrailsAsync(DbContextEventData eventData, CancellationToken cancellationToken) { if (eventData.Context == null) return; eventData.Context.ChangeTracker.DetectChanges(); - var trails = new List(); + var trails = new List(); var utcNow = timeProvider.GetUtcNow(); foreach (var entry in eventData.Context.ChangeTracker.Entries().Where(x => x.State is EntityState.Added or EntityState.Deleted or EntityState.Modified).ToList()) { var userId = currentUser.GetUserId(); - var audit = new AuditTrail() + var audit = new Trail() { Id = Guid.NewGuid(), EntityName = entry.Entity.GetType().Name, @@ -100,7 +100,7 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData) trails.Add(audit); } if (trails.Count == 0) return; - await publisher.Publish(new AuditPublishedEvent(trails)); + await publisher.PublishAsync(new AuditPublishedEvent(trails), cancellationToken); } public void UpdateEntities(DbContext? context) diff --git a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs index 677f582d6..b015065d3 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs @@ -5,9 +5,9 @@ namespace FSH.Framework.Auditing.Infrastructure.Services; public class AuditService(IAuditingDbContext context) : IAuditService { - public async Task> GetUserTrailsAsync(Guid userId) + public async Task> GetUserTrailsAsync(Guid userId) { - var trails = await context.AuditTrails + var trails = await context.Trails .Where(a => a.UserId == userId) .OrderByDescending(a => a.DateTime) .Take(250) From 4ec0617761d44db855393a747482d6b564717e73 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 16:44:03 +0530 Subject: [PATCH 15/54] better cqrs structure --- src/Directory.Packages.props | 2 + .../Auditing.Contracts.csproj | 16 ++ .../Enums/AuditOperation.cs | 2 +- .../Events/AuditPublishedEvent.cs | 5 +- .../Dtos => Auditing.Contracts}/Trail.cs | 5 +- .../Abstractions/IAuditService.cs | 2 +- .../Abstractions/IAuditingDbContext.cs | 2 +- .../Auditing.Core/Auditing.Core.csproj | 1 + .../Auditing.Endpoints/AuditingModule.cs | 4 +- .../Auditing.Endpoints/v1/GetUserTrails.cs | 46 ----- .../v1/GetUserTrails/GetUserTrailsEndpoint.cs | 28 +++ .../v1/GetUserTrails/GetUserTrailsHandler.cs | 13 ++ .../v1/GetUserTrails/GetUserTrailsQuery.cs | 4 + .../v1/GetUserTrails/GetUserTrailsResponse.cs | 4 + .../GetUserTrails/GetUserTrailsValidator.cs | 10 + src/framework/FSH.Framework.sln | 7 + .../Identity.Core/Tokens/ITokenService.cs | 1 - .../Tokens/Generate/TokenGenerationCommand.cs | 5 + .../Generate/TokenGenerationEndpoint.cs | 18 +- .../Tokens/Generate/TokenGenerationHandler.cs | 21 ++ .../TokenGenerationRequestValidator.cs | 18 -- .../Generate/TokenGenerationResponse.cs | 5 + .../Generate/TokenGenerationValidator.cs | 17 ++ .../Identity.Infrastructure.csproj | 3 + .../Tokens/TokenService.cs | 186 ++++++++++++++++++ 25 files changed, 341 insertions(+), 84 deletions(-) create mode 100644 src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj rename src/framework/Auditing/{Auditing.Core => Auditing.Contracts}/Enums/AuditOperation.cs (63%) rename src/framework/Auditing/{Auditing.Core => Auditing.Contracts}/Events/AuditPublishedEvent.cs (61%) rename src/framework/Auditing/{Auditing.Core/Dtos => Auditing.Contracts}/Trail.cs (93%) delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsEndpoint.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs create mode 100644 src/framework/Identity/Identity.Infrastructure/Tokens/TokenService.cs diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index b45d4cd42..8a84537f4 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -31,6 +31,7 @@ + @@ -49,6 +50,7 @@ + diff --git a/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj b/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj new file mode 100644 index 000000000..3582910e3 --- /dev/null +++ b/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj @@ -0,0 +1,16 @@ + + + FSH.Framework.Auditing.Contracts + FSH.Framework.Auditing.Contracts + + + net9.0 + enable + enable + + + + + + + diff --git a/src/framework/Auditing/Auditing.Core/Enums/AuditOperation.cs b/src/framework/Auditing/Auditing.Contracts/Enums/AuditOperation.cs similarity index 63% rename from src/framework/Auditing/Auditing.Core/Enums/AuditOperation.cs rename to src/framework/Auditing/Auditing.Contracts/Enums/AuditOperation.cs index a5e99f175..de953a2e4 100644 --- a/src/framework/Auditing/Auditing.Core/Enums/AuditOperation.cs +++ b/src/framework/Auditing/Auditing.Contracts/Enums/AuditOperation.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Auditing.Core.Enums; +namespace FSH.Framework.Auditing.Contracts.Enums; public enum AuditOperation { None = 0, diff --git a/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs b/src/framework/Auditing/Auditing.Contracts/Events/AuditPublishedEvent.cs similarity index 61% rename from src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs rename to src/framework/Auditing/Auditing.Contracts/Events/AuditPublishedEvent.cs index d086a582a..c6fdea919 100644 --- a/src/framework/Auditing/Auditing.Core/Events/AuditPublishedEvent.cs +++ b/src/framework/Auditing/Auditing.Contracts/Events/AuditPublishedEvent.cs @@ -1,7 +1,6 @@ -using FSH.Framework.Auditing.Core.Dtos; -using FSH.Framework.Core.Messaging.Events; +using FSH.Framework.Core.Messaging.Events; -namespace FSH.Framework.Auditing.Core.Events; +namespace FSH.Framework.Auditing.Contracts.Events; public class AuditPublishedEvent : INotification { diff --git a/src/framework/Auditing/Auditing.Core/Dtos/Trail.cs b/src/framework/Auditing/Auditing.Contracts/Trail.cs similarity index 93% rename from src/framework/Auditing/Auditing.Core/Dtos/Trail.cs rename to src/framework/Auditing/Auditing.Contracts/Trail.cs index 3a8752114..fd550b973 100644 --- a/src/framework/Auditing/Auditing.Core/Dtos/Trail.cs +++ b/src/framework/Auditing/Auditing.Contracts/Trail.cs @@ -1,9 +1,9 @@ using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json; -using FSH.Framework.Auditing.Core.Enums; +using FSH.Framework.Auditing.Contracts.Enums; -namespace FSH.Framework.Auditing.Core.Dtos; +namespace FSH.Framework.Auditing.Contracts; public class Trail { @@ -11,6 +11,7 @@ public class Trail public Guid UserId { get; set; } public DateTimeOffset DateTime { get; set; } public AuditOperation Operation { get; set; } // e.g., "Create", "Update", "Delete" + public required string Description { get; set; } public string? EntityName { get; set; } // Name of the entity/table affected // Store dictionaries as JSON in the database diff --git a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs index 57363c791..2ab2cdf9b 100644 --- a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs +++ b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Auditing.Contracts; namespace FSH.Framework.Auditing.Core.Abstractions; public interface IAuditService diff --git a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs index d7698669f..475012522 100644 --- a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs +++ b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Auditing.Contracts; using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Auditing.Core.Abstractions; diff --git a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj index 62146b41a..9a4dcd97b 100644 --- a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj +++ b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj @@ -13,6 +13,7 @@ + diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs index c95f7f985..c399e2148 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -1,7 +1,7 @@ using System.Reflection; using Asp.Versioning; using Asp.Versioning.Builder; -using FSH.Framework.Auditing.Endpoints.v1; +using FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; using FSH.Framework.Infrastructure.Messaging.CQRS; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; @@ -35,7 +35,7 @@ public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuil .WithApiVersionSet(apiVersionSet); // v1 endpoints - GetUserTrails.MapEndpoint(group); + GetUserTrailsEndpoint.MapEndpoint(group); return endpoints; } diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs deleted file mode 100644 index 7518a5ada..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs +++ /dev/null @@ -1,46 +0,0 @@ -using FluentValidation; -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Auditing.Core.Dtos; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Auditing.Endpoints.v1; - -public static class GetUserTrails -{ - public sealed record Query(Guid UserId) : IQuery; - public sealed record Response(IReadOnlyList AuditTrails); - public sealed class Validator : AbstractValidator - { - public Validator() - { - RuleFor(x => x.UserId).NotEmpty(); - } - } - public static RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/users/{userId:guid}/trails", async ( - Guid id, - IQueryDispatcher dispatcher, - CancellationToken cancellationToken) => - { - var result = await dispatcher.SendAsync(new Query(id), cancellationToken); - return TypedResults.Ok(result); - }) - .WithName(nameof(GetUserTrails)) - .WithSummary("Get user's audit trail details") - .RequirePermission("Permissions.AuditTrails.View") - .WithDescription("Get user's audit trail details."); - } - public sealed class Handler(IAuditService auditService) : IQueryHandler - { - public async Task HandleAsync(Query request, CancellationToken cancellationToken = default) - { - var trails = await auditService.GetUserTrailsAsync(request.UserId); - return new Response(trails); - } - } -} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsEndpoint.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsEndpoint.cs new file mode 100644 index 000000000..0cf6008e6 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsEndpoint.cs @@ -0,0 +1,28 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +public static class GetUserTrailsEndpoint +{ + public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/users/{userId:guid}/trails", async ( + Guid userId, + IQueryDispatcher dispatcher, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync( + new GetUserTrailsQuery(userId), cancellationToken); + + return TypedResults.Ok(result); + }) + .WithName("GetUserTrails") + .WithSummary("Get user's audit trail details") + .WithDescription("Returns the audit trail details for a specific user.") + .RequirePermission("Permissions.AuditTrails.View"); + } +} + diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs new file mode 100644 index 000000000..da3b4a524 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs @@ -0,0 +1,13 @@ +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +public sealed class GetUserTrailsHandler(IAuditService auditService) + : IQueryHandler +{ + public async Task HandleAsync(GetUserTrailsQuery query, CancellationToken cancellationToken = default) + { + var trails = await auditService.GetUserTrailsAsync(query.UserId); + return new GetUserTrailsResponse(trails); + } +} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs new file mode 100644 index 000000000..117c0da22 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +public sealed record GetUserTrailsQuery(Guid UserId) : IQuery; diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs new file mode 100644 index 000000000..179cded9f --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Auditing.Contracts; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +public sealed record GetUserTrailsResponse(IReadOnlyList AuditTrails); diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs new file mode 100644 index 000000000..f1a15f319 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs @@ -0,0 +1,10 @@ +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +using FluentValidation; + +public sealed class GetUserTrailsValidator : AbstractValidator +{ + public GetUserTrailsValidator() + { + RuleFor(x => x.UserId).NotEmpty(); + } +} diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index ac7d5fa38..702750c03 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -37,6 +37,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Infrastructure", "Te EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Contracts", "Auditing\Auditing.Contracts\Auditing.Contracts.csproj", "{7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -95,6 +97,10 @@ Global {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Release|Any CPU.Build.0 = Release|Any CPU + {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -112,6 +118,7 @@ Global {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6} = {24E922E3-8C91-43A1-A110-D8F5276566BA} {86BC889E-322A-460E-81B6-601EE65B37C1} = {24E922E3-8C91-43A1-A110-D8F5276566BA} {F8AE32F3-31B9-4962-BE7A-1326BD13B739} = {24E922E3-8C91-43A1-A110-D8F5276566BA} + {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55} = {E5141F38-2D08-44DA-9A6C-B96890515168} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} diff --git a/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs index b6acb2a39..947ef8fab 100644 --- a/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs +++ b/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs @@ -3,5 +3,4 @@ public interface ITokenService { Task GenerateTokenAsync(TokenGenerationRequest request, string ipAddress, CancellationToken cancellationToken); Task RefreshTokenAsync(TokenRefreshRequest request, string ipAddress, CancellationToken cancellationToken); - } diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs new file mode 100644 index 000000000..e47c97146 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs @@ -0,0 +1,5 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; +public sealed record TokenGenerationCommand(string Email, string Password) + : ICommand; diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs index cb6b5cba9..821d5cd3b 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs @@ -1,5 +1,4 @@ -using FSH.Framework.Identity.Core.Tokens; -using FSH.Framework.Shared.Extensions; +using FSH.Framework.Core.Messaging.CQRS; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -9,18 +8,19 @@ public static class TokenGenerationEndpoint { internal static RouteHandlerBuilder MapTokenGenerationEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/", (TokenGenerationRequest request, + return endpoints.MapPost("/", async ( + TokenGenerationCommand command, string tenant, - ITokenService service, + ICommandDispatcher dispatcher, HttpContext context, CancellationToken cancellationToken) => { - string ip = context.GetIpAddress(); - return service.GenerateTokenAsync(request, ip!, cancellationToken); + var result = await dispatcher.SendAsync(command, cancellationToken); + return TypedResults.Ok(result); }) - .WithName(nameof(TokenGenerationEndpoint)) - .WithSummary("generate JWTs") - .WithDescription("generate JWTs") + .WithName("TokenGeneration") + .WithSummary("Generate JWTs") + .WithDescription("Generates access and refresh tokens.") .AllowAnonymous(); } } diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs new file mode 100644 index 000000000..bb3d8ddc4 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs @@ -0,0 +1,21 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Shared.Extensions; +using Microsoft.AspNetCore.Http; + +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; +public sealed class TokenGenerationHandler( + ITokenService tokenService, + HttpContext context) + : ICommandHandler +{ + public async Task HandleAsync(TokenGenerationCommand command, CancellationToken cancellationToken = default) + { + var request = new TokenGenerationRequest(command.Email, command.Password); + string ip = context.GetIpAddress(); + + var token = await tokenService.GenerateTokenAsync(request, ip, cancellationToken); + + return new TokenGenerationResponse(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); + } +} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs deleted file mode 100644 index c42322215..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationRequestValidator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using FluentValidation; -using FSH.Framework.Identity.Core.Tokens; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; -public class TokenGenerationRequestValidator : AbstractValidator -{ - public TokenGenerationRequestValidator() - { - RuleFor(p => p.Email) - .Cascade(CascadeMode.Stop) - .NotEmpty() - .EmailAddress(); - - RuleFor(p => p.Password) - .Cascade(CascadeMode.Stop) - .NotEmpty(); - } -} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs new file mode 100644 index 000000000..2661aa7e3 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; +public sealed record TokenGenerationResponse( + string Token, + string RefreshToken, + DateTime RefreshTokenExpiryTime); diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs new file mode 100644 index 000000000..e55abe7a3 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs @@ -0,0 +1,17 @@ +namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; +using FluentValidation; + +public sealed class TokenGenerationValidator : AbstractValidator +{ + public TokenGenerationValidator() + { + RuleFor(p => p.Email) + .Cascade(CascadeMode.Stop) + .NotEmpty() + .EmailAddress(); + + RuleFor(p => p.Password) + .Cascade(CascadeMode.Stop) + .NotEmpty(); + } +} diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index 31c1f1831..6148daf12 100644 --- a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -9,6 +9,7 @@ enable + @@ -18,5 +19,7 @@ + + diff --git a/src/framework/Identity/Identity.Infrastructure/Tokens/TokenService.cs b/src/framework/Identity/Identity.Infrastructure/Tokens/TokenService.cs new file mode 100644 index 000000000..edbf8cfd2 --- /dev/null +++ b/src/framework/Identity/Identity.Infrastructure/Tokens/TokenService.cs @@ -0,0 +1,186 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using Finbuckle.MultiTenant.Abstractions; +using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Contracts.Enums; +using FSH.Framework.Auditing.Contracts.Events; +using FSH.Framework.Core.Exceptions; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Shared.Constants; +using FSH.Framework.Shared.Multitenancy; +using MediatR; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; + +namespace FSH.Framework.Identity.Infrastructure.Tokens; +public sealed class TokenService : ITokenService +{ + private readonly UserManager _userManager; + private readonly IMultiTenantContextAccessor? _multiTenantContextAccessor; + private readonly JwtOptions _jwtOptions; + private readonly IPublisher _publisher; + public TokenService(IOptions jwtOptions, UserManager userManager, IMultiTenantContextAccessor? multiTenantContextAccessor, IPublisher publisher) + { + _jwtOptions = jwtOptions.Value; + _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); + _multiTenantContextAccessor = multiTenantContextAccessor; + _publisher = publisher; + } + + public async Task GenerateTokenAsync(TokenGenerationRequest request, string ipAddress, CancellationToken cancellationToken) + { + var currentTenant = _multiTenantContextAccessor!.MultiTenantContext.TenantInfo; + if (currentTenant == null) throw new UnauthorizedException(); + if (string.IsNullOrWhiteSpace(currentTenant.Id) + || await _userManager.FindByEmailAsync(request.Email.Trim().Normalize()) is not { } user + || !await _userManager.CheckPasswordAsync(user, request.Password)) + { + throw new UnauthorizedException(); + } + + if (!user.IsActive) + { + throw new UnauthorizedException("user is deactivated"); + } + + if (!user.EmailConfirmed) + { + throw new UnauthorizedException("email not confirmed"); + } + + if (currentTenant.Id != TenantConstants.Root.Id) + { + if (!currentTenant.IsActive) + { + throw new UnauthorizedException($"tenant {currentTenant.Id} is deactivated"); + } + + if (DateTime.UtcNow > currentTenant.ValidUpto) + { + throw new UnauthorizedException($"tenant {currentTenant.Id} validity has expired"); + } + } + + return await GenerateTokensAndUpdateUser(user, ipAddress); + } + + + public async Task RefreshTokenAsync(TokenRefreshRequest request, string ipAddress, CancellationToken cancellationToken) + { + var userPrincipal = GetPrincipalFromExpiredToken(request.Token); + var userId = _userManager.GetUserId(userPrincipal)!; + var user = await _userManager.FindByIdAsync(userId); + if (user is null) + { + throw new UnauthorizedException(); + } + + if (user.RefreshToken != request.RefreshToken || user.RefreshTokenExpiryTime <= DateTime.UtcNow) + { + throw new UnauthorizedException("Invalid Refresh Token"); + } + + return await GenerateTokensAndUpdateUser(user, ipAddress); + } + private async Task GenerateTokensAndUpdateUser(FshUser user, string ipAddress) + { + string token = GenerateJwt(user, ipAddress); + + user.RefreshToken = GenerateRefreshToken(); + user.RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(_jwtOptions.RefreshTokenExpirationInDays); + + await _userManager.UpdateAsync(user); + + await _publisher.Publish(new AuditPublishedEvent(new List + { + new() { + Id = Guid.NewGuid(), + Operation = AuditOperation.Create, + Description = "Token Generated.", + EntityName = "Identity", + UserId = new Guid(user.Id), + DateTime = DateTime.UtcNow, + } + })); + + + return new TokenDto(token, user.RefreshToken, user.RefreshTokenExpiryTime); + } + + private string GenerateJwt(FshUser user, string ipAddress) => + GenerateEncryptedToken(GetSigningCredentials(), GetClaims(user, ipAddress)); + + private SigningCredentials GetSigningCredentials() + { + byte[] secret = Encoding.UTF8.GetBytes(_jwtOptions.Key); + return new SigningCredentials(new SymmetricSecurityKey(secret), SecurityAlgorithms.HmacSha256); + } + + private string GenerateEncryptedToken(SigningCredentials signingCredentials, IEnumerable claims) + { + var token = new JwtSecurityToken( + claims: claims, + expires: DateTime.UtcNow.AddMinutes(_jwtOptions.TokenExpirationInMinutes), + signingCredentials: signingCredentials, + issuer: JwtAuthConstants.Issuer, + audience: JwtAuthConstants.Audience + ); + var tokenHandler = new JwtSecurityTokenHandler(); + return tokenHandler.WriteToken(token); + } + + private List GetClaims(FshUser user, string ipAddress) => + new() + { + new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new(ClaimTypes.NameIdentifier, user.Id), + new(ClaimTypes.Email, user.Email!), + new(ClaimTypes.Name, user.FirstName ?? string.Empty), + new(ClaimTypes.MobilePhone, user.PhoneNumber ?? string.Empty), + new(FshClaims.Fullname, $"{user.FirstName} {user.LastName}"), + new(ClaimTypes.Surname, user.LastName ?? string.Empty), + new(FshClaims.IpAddress, ipAddress), + new(FshClaims.Tenant, _multiTenantContextAccessor!.MultiTenantContext.TenantInfo!.Id), + new(FshClaims.ImageUrl, user.ImageUrl == null ? string.Empty : user.ImageUrl.ToString()) + }; + private static string GenerateRefreshToken() + { + byte[] randomNumber = new byte[32]; + using var rng = RandomNumberGenerator.Create(); + rng.GetBytes(randomNumber); + return Convert.ToBase64String(randomNumber); + } + + private ClaimsPrincipal GetPrincipalFromExpiredToken(string token) + { +#pragma warning disable CA5404 // Do not disable token validation checks + var tokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Key)), + ValidateIssuer = true, + ValidateAudience = true, + ValidAudience = JwtAuthConstants.Audience, + ValidIssuer = JwtAuthConstants.Issuer, + RoleClaimType = ClaimTypes.Role, + ClockSkew = TimeSpan.Zero, + ValidateLifetime = false + }; +#pragma warning restore CA5404 // Do not disable token validation checks + var tokenHandler = new JwtSecurityTokenHandler(); + var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken); + if (securityToken is not JwtSecurityToken jwtSecurityToken || + !jwtSecurityToken.Header.Alg.Equals( + SecurityAlgorithms.HmacSha256, + StringComparison.OrdinalIgnoreCase)) + { + throw new UnauthorizedException("invalid token"); + } + + return principal; + } +} From 137b294d195ac9b5e74188f72ec8c36d2308291f Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 21:32:28 +0530 Subject: [PATCH 16/54] remove mediatr --- src/framework/Application/Application.csproj | 1 - .../Auditing.Endpoints/AuditingModule.cs | 2 +- ...lsEndpoint.cs => GetUserTrails.Endpoint.cs} | 6 +++--- .../v1/GetUserTrails/GetUserTrails.Handler.cs | 18 ++++++++++++++++++ .../v1/GetUserTrails/GetUserTrails.Query.cs | 7 +++++++ .../v1/GetUserTrails/GetUserTrails.Response.cs | 7 +++++++ .../GetUserTrails/GetUserTrails.Validator.cs | 12 ++++++++++++ .../v1/GetUserTrails/GetUserTrailsHandler.cs | 13 ------------- .../v1/GetUserTrails/GetUserTrailsQuery.cs | 4 ---- .../v1/GetUserTrails/GetUserTrailsResponse.cs | 4 ---- .../v1/GetUserTrails/GetUserTrailsValidator.cs | 10 ---------- src/framework/Core/Core.csproj | 1 - .../Identity.Endpoints.csproj | 1 - .../Infrastructure/Infrastructure.csproj | 2 -- 14 files changed, 48 insertions(+), 40 deletions(-) rename src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/{GetUserTrailsEndpoint.cs => GetUserTrails.Endpoint.cs} (80%) create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs diff --git a/src/framework/Application/Application.csproj b/src/framework/Application/Application.csproj index 71327fe02..638eba449 100644 --- a/src/framework/Application/Application.csproj +++ b/src/framework/Application/Application.csproj @@ -9,7 +9,6 @@ enable - diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs index c399e2148..710592a01 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -35,7 +35,7 @@ public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuil .WithApiVersionSet(apiVersionSet); // v1 endpoints - GetUserTrailsEndpoint.MapEndpoint(group); + GetUserTrails.MapEndpoint(group); return endpoints; } diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsEndpoint.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Endpoint.cs similarity index 80% rename from src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsEndpoint.cs rename to src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Endpoint.cs index 0cf6008e6..870591691 100644 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsEndpoint.cs +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Endpoint.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -public static class GetUserTrailsEndpoint +public static partial class GetUserTrails { public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) { @@ -14,8 +14,8 @@ public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoin IQueryDispatcher dispatcher, CancellationToken cancellationToken) => { - var result = await dispatcher.SendAsync( - new GetUserTrailsQuery(userId), cancellationToken); + var result = await dispatcher.SendAsync( + new Query(userId), cancellationToken); return TypedResults.Ok(result); }) diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs new file mode 100644 index 000000000..54ae7a2c4 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs @@ -0,0 +1,18 @@ +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; + +public static partial class GetUserTrails +{ + public sealed class Handler(IAuditService auditService) + : IQueryHandler + { + public async Task HandleAsync(Query query, CancellationToken cancellationToken = default) + { + var trails = await auditService.GetUserTrailsAsync(query.UserId); + return new Response(trails); + } + } +} + diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs new file mode 100644 index 000000000..251bd53e8 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs @@ -0,0 +1,7 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +public static partial class GetUserTrails +{ + public sealed record Query(Guid UserId) : IQuery; +} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs new file mode 100644 index 000000000..e3f83ff6b --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs @@ -0,0 +1,7 @@ +using FSH.Framework.Auditing.Contracts; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +public static partial class GetUserTrails +{ + public sealed record Response(IReadOnlyList AuditTrails); +} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs new file mode 100644 index 000000000..28ef66186 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs @@ -0,0 +1,12 @@ +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +using FluentValidation; +public static partial class GetUserTrails +{ + public sealed class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.UserId).NotEmpty(); + } + } +} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs deleted file mode 100644 index da3b4a524..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Core.Messaging.CQRS; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -public sealed class GetUserTrailsHandler(IAuditService auditService) - : IQueryHandler -{ - public async Task HandleAsync(GetUserTrailsQuery query, CancellationToken cancellationToken = default) - { - var trails = await auditService.GetUserTrailsAsync(query.UserId); - return new GetUserTrailsResponse(trails); - } -} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs deleted file mode 100644 index 117c0da22..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsQuery.cs +++ /dev/null @@ -1,4 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -public sealed record GetUserTrailsQuery(Guid UserId) : IQuery; diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs deleted file mode 100644 index 179cded9f..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsResponse.cs +++ /dev/null @@ -1,4 +0,0 @@ -using FSH.Framework.Auditing.Contracts; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -public sealed record GetUserTrailsResponse(IReadOnlyList AuditTrails); diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs deleted file mode 100644 index f1a15f319..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrailsValidator.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -using FluentValidation; - -public sealed class GetUserTrailsValidator : AbstractValidator -{ - public GetUserTrailsValidator() - { - RuleFor(x => x.UserId).NotEmpty(); - } -} diff --git a/src/framework/Core/Core.csproj b/src/framework/Core/Core.csproj index 2bd4670f5..e97b22185 100644 --- a/src/framework/Core/Core.csproj +++ b/src/framework/Core/Core.csproj @@ -5,7 +5,6 @@ - diff --git a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj index 30876e2b9..2bb99b80b 100644 --- a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj +++ b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj @@ -10,7 +10,6 @@ - diff --git a/src/framework/Infrastructure/Infrastructure.csproj b/src/framework/Infrastructure/Infrastructure.csproj index 33601f76b..5b8ddef5b 100644 --- a/src/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Infrastructure/Infrastructure.csproj @@ -54,9 +54,7 @@ - - From fb14de156474e077348006a9d3d549769f313aec Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 22:16:15 +0530 Subject: [PATCH 17/54] cleanup --- src/.dockerignore | 32 -- src/.editorconfig | 397 ------------------ src/Directory.Build.props | 18 - src/Dockerfile.Blazor | 13 - src/FSH.Starter.sln | 287 ------------- src/GetToken.http | 10 - src/framework/.editorconfig | 288 +++++++++++++ .../GetUserTrails/GetUserTrails.Validator.cs | 6 +- src/framework/Directory.Build.props | 36 ++ src/{ => framework}/Directory.Packages.props | 8 +- src/framework/FSH.Framework.sln | 7 + .../Storage/LocalStorageService.cs | 5 +- .../Tenant.Endpoints/Tenant.Endpoints.csproj | 1 - src/global.json | 2 +- 14 files changed, 342 insertions(+), 768 deletions(-) delete mode 100644 src/.dockerignore delete mode 100644 src/.editorconfig delete mode 100644 src/Directory.Build.props delete mode 100644 src/Dockerfile.Blazor delete mode 100644 src/FSH.Starter.sln delete mode 100644 src/GetToken.http create mode 100644 src/framework/.editorconfig create mode 100644 src/framework/Directory.Build.props rename src/{ => framework}/Directory.Packages.props (95%) diff --git a/src/.dockerignore b/src/.dockerignore deleted file mode 100644 index 3aae53927..000000000 --- a/src/.dockerignore +++ /dev/null @@ -1,32 +0,0 @@ -# Include any files or directories that you don't want to be copied to your -# container here (e.g., local build artifacts, temporary files, etc.). -# -# For more help, visit the .dockerignore file reference guide at -# https://docs.docker.com/engine/reference/builder/#dockerignore-file - -**/.DS_Store -**/.classpath -**/.dockerignore -**/.env -**/.git -**/.gitignore -**/.project -**/.settings -**/.toolstarget -**/.vs -**/.vscode -**/*.*proj.user -**/*.dbmdl -**/*.jfm -**/bin -**/charts -**/docker-compose* -**/compose* -**/Dockerfile* -**/node_modules -**/npm-debug.log -**/obj -**/secrets.dev.yaml -**/values.dev.yaml -LICENSE -README.md diff --git a/src/.editorconfig b/src/.editorconfig deleted file mode 100644 index b3fa9a701..000000000 --- a/src/.editorconfig +++ /dev/null @@ -1,397 +0,0 @@ -root = true - -# All files -[*] -indent_style = space - -# Xml files -[*.{xml,csproj,props,targets,ruleset,nuspec,resx}] -indent_size = 2 - -# Json files -[*.{json,config,nswag}] -indent_size = 2 - -# C# files -[*.cs] - -#### Core EditorConfig Options #### - -# Indentation and spacing -indent_size = 4 -tab_width = 4 - -# New line preferences -end_of_line = lf -insert_final_newline = true - -#### .NET Coding Conventions #### -[*.{cs,vb}] - -# Organize usings -dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = true -file_header_template = unset - -# this. and Me. preferences -dotnet_style_qualification_for_event = false:silent -dotnet_style_qualification_for_field = false:silent -dotnet_style_qualification_for_method = false:silent -dotnet_style_qualification_for_property = false:silent - -# Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true:silent -dotnet_style_predefined_type_for_member_access = true:silent - -# Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent - -# Modifier preferences -dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent - -# Expression-level preferences -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_object_initializer = true:suggestion -dotnet_style_operator_placement_when_wrapping = beginning_of_line -dotnet_style_prefer_auto_properties = true:suggestion -dotnet_style_prefer_compound_assignment = true:suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion -dotnet_style_prefer_conditional_expression_over_return = true:suggestion -dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_inferred_tuple_names = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion -dotnet_style_prefer_simplified_boolean_expressions = true:suggestion -dotnet_style_prefer_simplified_interpolation = true:suggestion - -# Field preferences -dotnet_style_readonly_field = true:warning - -# Parameter preferences -dotnet_code_quality_unused_parameters = all:suggestion - -# Suppression preferences -dotnet_remove_unnecessary_suppression_exclusions = none - -#### C# Coding Conventions #### -[*.cs] - -# var preferences -csharp_style_var_elsewhere = false:silent -csharp_style_var_for_built_in_types = false:silent -csharp_style_var_when_type_is_apparent = false:silent - -# Expression-bodied members -csharp_style_expression_bodied_accessors = true:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_lambdas = true:suggestion -csharp_style_expression_bodied_local_functions = false:silent -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent - -# Pattern matching preferences -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_prefer_not_pattern = true:suggestion -csharp_style_prefer_pattern_matching = true:silent -csharp_style_prefer_switch_expression = true:suggestion - -# Null-checking preferences -csharp_style_conditional_delegate_call = true:suggestion - -# Modifier preferences -csharp_prefer_static_local_function = true:warning -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent - -# Code-block preferences -csharp_prefer_braces = true:silent -csharp_prefer_simple_using_statement = true:suggestion - -# Expression-level preferences -csharp_prefer_simple_default_expression = true:suggestion -csharp_style_deconstructed_variable_declaration = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion -csharp_style_pattern_local_over_anonymous_function = true:suggestion -csharp_style_prefer_index_operator = true:suggestion -csharp_style_prefer_range_operator = true:suggestion -csharp_style_throw_expression = true:suggestion -csharp_style_unused_value_assignment_preference = discard_variable:suggestion -csharp_style_unused_value_expression_statement_preference = discard_variable:silent - -# 'using' directive preferences -csharp_using_directive_placement = outside_namespace:silent - -#### C# Formatting Rules #### - -# New line preferences -csharp_new_line_before_catch = true -csharp_new_line_before_else = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_open_brace = all -csharp_new_line_between_query_expression_clauses = true - -# Indentation preferences -csharp_indent_block_contents = true -csharp_indent_braces = false -csharp_indent_case_contents = true -csharp_indent_case_contents_when_block = true -csharp_indent_labels = one_less_than_current -csharp_indent_switch_labels = true - -# Space preferences -csharp_space_after_cast = false -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_after_comma = true -csharp_space_after_dot = false -csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = false -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_before_comma = false -csharp_space_before_dot = false -csharp_space_before_open_square_brackets = false -csharp_space_before_semicolon_in_for_statement = false -csharp_space_between_empty_square_brackets = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_declaration_name_and_open_parenthesis = false -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_parentheses = false -csharp_space_between_square_brackets = false - -# Wrapping preferences -csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = true -csharp_style_namespace_declarations = file_scoped:silent -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_prefer_null_check_over_type_check = true:suggestion -csharp_style_prefer_local_over_anonymous_function = 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 -dotnet_diagnostic.CA1032.severity = none -dotnet_diagnostic.CA1812.severity = none -dotnet_diagnostic.S6667.severity = none - -#### Naming styles #### -[*.{cs,vb}] - -# Naming rules - -dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces -dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion -dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces -dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase - -dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion -dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters -dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase - -dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods -dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties -dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.events_should_be_pascalcase.symbols = events -dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion -dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables -dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase - -dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion -dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants -dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase - -dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion -dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters -dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase - -dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields -dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion -dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields -dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase - -dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion -dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields -dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase - -dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields -dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields -dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields -dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields -dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums -dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions -dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase - -dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion -dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members -dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase - -# Symbol specifications - -dotnet_naming_symbols.interfaces.applicable_kinds = interface -dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interfaces.required_modifiers = - -dotnet_naming_symbols.enums.applicable_kinds = enum -dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.enums.required_modifiers = - -dotnet_naming_symbols.events.applicable_kinds = event -dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.events.required_modifiers = - -dotnet_naming_symbols.methods.applicable_kinds = method -dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.methods.required_modifiers = - -dotnet_naming_symbols.properties.applicable_kinds = property -dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.properties.required_modifiers = - -dotnet_naming_symbols.public_fields.applicable_kinds = field -dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal -dotnet_naming_symbols.public_fields.required_modifiers = - -dotnet_naming_symbols.private_fields.applicable_kinds = field -dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected -dotnet_naming_symbols.private_fields.required_modifiers = - -dotnet_naming_symbols.private_static_fields.applicable_kinds = field -dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected -dotnet_naming_symbols.private_static_fields.required_modifiers = static - -dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum -dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types_and_namespaces.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.type_parameters.applicable_kinds = namespace -dotnet_naming_symbols.type_parameters.applicable_accessibilities = * -dotnet_naming_symbols.type_parameters.required_modifiers = - -dotnet_naming_symbols.private_constant_fields.applicable_kinds = field -dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected -dotnet_naming_symbols.private_constant_fields.required_modifiers = const - -dotnet_naming_symbols.local_variables.applicable_kinds = local -dotnet_naming_symbols.local_variables.applicable_accessibilities = local -dotnet_naming_symbols.local_variables.required_modifiers = - -dotnet_naming_symbols.local_constants.applicable_kinds = local -dotnet_naming_symbols.local_constants.applicable_accessibilities = local -dotnet_naming_symbols.local_constants.required_modifiers = const - -dotnet_naming_symbols.parameters.applicable_kinds = parameter -dotnet_naming_symbols.parameters.applicable_accessibilities = * -dotnet_naming_symbols.parameters.required_modifiers = - -dotnet_naming_symbols.public_constant_fields.applicable_kinds = field -dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal -dotnet_naming_symbols.public_constant_fields.required_modifiers = const - -dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field -dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal -dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static - -dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field -dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected -dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static - -dotnet_naming_symbols.local_functions.applicable_kinds = local_function -dotnet_naming_symbols.local_functions.applicable_accessibilities = * -dotnet_naming_symbols.local_functions.required_modifiers = - -# Naming styles - -dotnet_naming_style.pascalcase.required_prefix = -dotnet_naming_style.pascalcase.required_suffix = -dotnet_naming_style.pascalcase.word_separator = -dotnet_naming_style.pascalcase.capitalization = pascal_case - -dotnet_naming_style.ipascalcase.required_prefix = I -dotnet_naming_style.ipascalcase.required_suffix = -dotnet_naming_style.ipascalcase.word_separator = -dotnet_naming_style.ipascalcase.capitalization = pascal_case - -dotnet_naming_style.tpascalcase.required_prefix = T -dotnet_naming_style.tpascalcase.required_suffix = -dotnet_naming_style.tpascalcase.word_separator = -dotnet_naming_style.tpascalcase.capitalization = pascal_case - -dotnet_naming_style._camelcase.required_prefix = _ -dotnet_naming_style._camelcase.required_suffix = -dotnet_naming_style._camelcase.word_separator = -dotnet_naming_style._camelcase.capitalization = camel_case - -dotnet_naming_style.camelcase.required_prefix = -dotnet_naming_style.camelcase.required_suffix = -dotnet_naming_style.camelcase.word_separator = -dotnet_naming_style.camelcase.capitalization = camel_case - -dotnet_naming_style.s_camelcase.required_prefix = s_ -dotnet_naming_style.s_camelcase.required_suffix = -dotnet_naming_style.s_camelcase.word_separator = -dotnet_naming_style.s_camelcase.capitalization = camel_case - -dotnet_style_namespace_match_folder = true:suggestion - -dotnet_diagnostic.CS1591.severity = none -dotnet_diagnostic.CA1724.severity = none -dotnet_diagnostic.CA1305.severity = none -dotnet_diagnostic.CA1040.severity = none -dotnet_diagnostic.CA1848.severity = none -dotnet_diagnostic.CA1034.severity = none -tab_width = 4 -indent_size = 4 -end_of_line = lf -dotnet_diagnostic.CA1711.severity = none -dotnet_diagnostic.CA1716.severity = none -dotnet_diagnostic.CA1062.severity = none -dotnet_diagnostic.CA1031.severity = none -dotnet_diagnostic.CA1861.severity = none -dotnet_diagnostic.CA2007.severity = none \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index cf4b4bb3d..000000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,18 +0,0 @@ - - - net9.0 - false - false - true - true - enable - enable - true - latest - All - 2.0.4-rc;latest - - - - - \ No newline at end of file diff --git a/src/Dockerfile.Blazor b/src/Dockerfile.Blazor deleted file mode 100644 index 2438ffea6..000000000 --- a/src/Dockerfile.Blazor +++ /dev/null @@ -1,13 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build-env -WORKDIR /app - -COPY . ./ -RUN dotnet publish ./apps/blazor/client/Client.csproj -c Release -o output - -FROM nginx:alpine -WORKDIR /usr/share/nginx/html -COPY --from=build-env /app/output/wwwroot . - -COPY ./apps/blazor/nginx.conf /etc/nginx/nginx.conf - -EXPOSE 80 \ No newline at end of file diff --git a/src/FSH.Starter.sln b/src/FSH.Starter.sln deleted file mode 100644 index 904c59f77..000000000 --- a/src/FSH.Starter.sln +++ /dev/null @@ -1,287 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{F3DF5AC5-8CDC-46D4-969D-1245A6880215}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A32CEFB3-4E50-401E-8835-787534414F41}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props - README.md = README.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Catalog", "Catalog", "{93324D12-DE1B-4C1B-934A-92AA140FF6F6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Todo", "Todo", "{79981A5A-207A-4A16-A21B-5E80394082F6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Framework", "_Framework", "{05248A38-0F34-4E59-A3D1-B07097987AFB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Migrations", "Migrations", "{12F8343D-20A6-4E24-B0F5-3A66F2228CF6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApi", "WebApi", "{CE64E92B-E088-46FB-9028-7FB6B67DEC55}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blazor", "Blazor", "{2B1F75CE-07A6-4C19-A2E3-F9E062CFDDFB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "api\framework\Infrastructure\Infrastructure.csproj", "{294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "api\framework\Core\Core.csproj", "{A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "api\server\Server.csproj", "{86BD3DF6-A3E9-4839-8036-813A20DC8AD6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSSQL", "api\migrations\MSSQL\MSSQL.csproj", "{ECCEA352-8953-49D6-8F87-8AB361499420}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PostgreSQL", "api\migrations\PostgreSQL\PostgreSQL.csproj", "{D64AD07C-A711-42D8-8653-EDCD7A825A44}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Todo", "api\modules\Todo\Todo.csproj", "{B3866EEF-8F46-4302-ABAC-A95EE2F27331}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.Application", "api\modules\Catalog\Catalog.Application\Catalog.Application.csproj", "{8C7DAF8E-F792-4092-8BBF-31A6B898B39A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.Domain", "api\modules\Catalog\Catalog.Domain\Catalog.Domain.csproj", "{B15705B5-041C-4F1E-8342-AD03182EDD42}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.Infrastructure", "api\modules\Catalog\Catalog.Infrastructure\Catalog.Infrastructure.csproj", "{89FE1C3B-29D3-48A8-8E7D-90C261D266C5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "apps\blazor\client\Client.csproj", "{BCE4A428-8B97-4B56-AE45-496EE3906667}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "apps\blazor\infrastructure\Infrastructure.csproj", "{27BEF279-AE73-43DC-92A9-FD7021A999D0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "apps\blazor\shared\Shared.csproj", "{34359707-CE66-4DF0-9EF4-D7544B615564}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aspire", "Aspire", "{D36E77BC-4568-4BC8-9506-1EFB7B1CD335}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceDefaults", "aspire\service-defaults\ServiceDefaults.csproj", "{990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Host", "aspire\host\Host.csproj", "{2119CE89-308D-4932-BFCE-8CDC0A05EB9E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{FE1B1E84-F993-4840-9CAB-9082EB523FDD}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auth", "Auth", "{F17769D7-0E41-4E80-BDD4-282EBE7B5199}" - ProjectSection(SolutionItems) = preProject - GetToken.http = GetToken.http - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Debug|x64.ActiveCfg = Debug|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Debug|x64.Build.0 = Debug|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Debug|x86.ActiveCfg = Debug|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Debug|x86.Build.0 = Debug|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Release|Any CPU.Build.0 = Release|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Release|x64.ActiveCfg = Release|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Release|x64.Build.0 = Release|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Release|x86.ActiveCfg = Release|Any CPU - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB}.Release|x86.Build.0 = Release|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Debug|x64.ActiveCfg = Debug|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Debug|x64.Build.0 = Debug|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Debug|x86.ActiveCfg = Debug|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Debug|x86.Build.0 = Debug|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Release|Any CPU.Build.0 = Release|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Release|x64.ActiveCfg = Release|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Release|x64.Build.0 = Release|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Release|x86.ActiveCfg = Release|Any CPU - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31}.Release|x86.Build.0 = Release|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Debug|x64.ActiveCfg = Debug|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Debug|x64.Build.0 = Debug|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Debug|x86.ActiveCfg = Debug|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Debug|x86.Build.0 = Debug|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Release|Any CPU.Build.0 = Release|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Release|x64.ActiveCfg = Release|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Release|x64.Build.0 = Release|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Release|x86.ActiveCfg = Release|Any CPU - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6}.Release|x86.Build.0 = Release|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Debug|x64.ActiveCfg = Debug|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Debug|x64.Build.0 = Debug|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Debug|x86.ActiveCfg = Debug|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Debug|x86.Build.0 = Debug|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Release|Any CPU.Build.0 = Release|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Release|x64.ActiveCfg = Release|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Release|x64.Build.0 = Release|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Release|x86.ActiveCfg = Release|Any CPU - {ECCEA352-8953-49D6-8F87-8AB361499420}.Release|x86.Build.0 = Release|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Debug|x64.ActiveCfg = Debug|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Debug|x64.Build.0 = Debug|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Debug|x86.ActiveCfg = Debug|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Debug|x86.Build.0 = Debug|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Release|Any CPU.Build.0 = Release|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Release|x64.ActiveCfg = Release|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Release|x64.Build.0 = Release|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Release|x86.ActiveCfg = Release|Any CPU - {D64AD07C-A711-42D8-8653-EDCD7A825A44}.Release|x86.Build.0 = Release|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Debug|x64.ActiveCfg = Debug|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Debug|x64.Build.0 = Debug|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Debug|x86.ActiveCfg = Debug|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Debug|x86.Build.0 = Debug|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Release|Any CPU.Build.0 = Release|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Release|x64.ActiveCfg = Release|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Release|x64.Build.0 = Release|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Release|x86.ActiveCfg = Release|Any CPU - {B3866EEF-8F46-4302-ABAC-A95EE2F27331}.Release|x86.Build.0 = Release|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Debug|x64.ActiveCfg = Debug|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Debug|x64.Build.0 = Debug|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Debug|x86.ActiveCfg = Debug|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Debug|x86.Build.0 = Debug|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Release|Any CPU.Build.0 = Release|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Release|x64.ActiveCfg = Release|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Release|x64.Build.0 = Release|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Release|x86.ActiveCfg = Release|Any CPU - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A}.Release|x86.Build.0 = Release|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Debug|x64.ActiveCfg = Debug|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Debug|x64.Build.0 = Debug|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Debug|x86.ActiveCfg = Debug|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Debug|x86.Build.0 = Debug|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Release|Any CPU.Build.0 = Release|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Release|x64.ActiveCfg = Release|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Release|x64.Build.0 = Release|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Release|x86.ActiveCfg = Release|Any CPU - {B15705B5-041C-4F1E-8342-AD03182EDD42}.Release|x86.Build.0 = Release|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Debug|x64.ActiveCfg = Debug|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Debug|x64.Build.0 = Debug|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Debug|x86.ActiveCfg = Debug|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Debug|x86.Build.0 = Debug|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Release|Any CPU.Build.0 = Release|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Release|x64.ActiveCfg = Release|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Release|x64.Build.0 = Release|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Release|x86.ActiveCfg = Release|Any CPU - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5}.Release|x86.Build.0 = Release|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Debug|x64.ActiveCfg = Debug|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Debug|x64.Build.0 = Debug|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Debug|x86.ActiveCfg = Debug|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Debug|x86.Build.0 = Debug|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Release|Any CPU.Build.0 = Release|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Release|x64.ActiveCfg = Release|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Release|x64.Build.0 = Release|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Release|x86.ActiveCfg = Release|Any CPU - {BCE4A428-8B97-4B56-AE45-496EE3906667}.Release|x86.Build.0 = Release|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Debug|x64.ActiveCfg = Debug|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Debug|x64.Build.0 = Debug|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Debug|x86.ActiveCfg = Debug|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Debug|x86.Build.0 = Debug|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Release|Any CPU.Build.0 = Release|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Release|x64.ActiveCfg = Release|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Release|x64.Build.0 = Release|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Release|x86.ActiveCfg = Release|Any CPU - {27BEF279-AE73-43DC-92A9-FD7021A999D0}.Release|x86.Build.0 = Release|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Debug|Any CPU.Build.0 = Debug|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Debug|x64.ActiveCfg = Debug|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Debug|x64.Build.0 = Debug|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Debug|x86.ActiveCfg = Debug|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Debug|x86.Build.0 = Debug|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Release|Any CPU.ActiveCfg = Release|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Release|Any CPU.Build.0 = Release|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Release|x64.ActiveCfg = Release|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Release|x64.Build.0 = Release|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Release|x86.ActiveCfg = Release|Any CPU - {34359707-CE66-4DF0-9EF4-D7544B615564}.Release|x86.Build.0 = Release|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Debug|x64.ActiveCfg = Debug|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Debug|x64.Build.0 = Debug|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Debug|x86.ActiveCfg = Debug|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Debug|x86.Build.0 = Debug|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Release|Any CPU.Build.0 = Release|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Release|x64.ActiveCfg = Release|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Release|x64.Build.0 = Release|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Release|x86.ActiveCfg = Release|Any CPU - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6}.Release|x86.Build.0 = Release|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Debug|x64.ActiveCfg = Debug|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Debug|x64.Build.0 = Debug|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Debug|x86.ActiveCfg = Debug|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Debug|x86.Build.0 = Debug|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Release|Any CPU.Build.0 = Release|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Release|x64.ActiveCfg = Release|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Release|x64.Build.0 = Release|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Release|x86.ActiveCfg = Release|Any CPU - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E}.Release|x86.Build.0 = Release|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Debug|x64.ActiveCfg = Debug|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Debug|x64.Build.0 = Debug|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Debug|x86.Build.0 = Debug|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Release|Any CPU.Build.0 = Release|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Release|x64.ActiveCfg = Release|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Release|x64.Build.0 = Release|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Release|x86.ActiveCfg = Release|Any CPU - {49AA63BF-3DBA-4490-9470-5AE0EB7F49F0}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {F3DF5AC5-8CDC-46D4-969D-1245A6880215} = {CE64E92B-E088-46FB-9028-7FB6B67DEC55} - {93324D12-DE1B-4C1B-934A-92AA140FF6F6} = {F3DF5AC5-8CDC-46D4-969D-1245A6880215} - {79981A5A-207A-4A16-A21B-5E80394082F6} = {F3DF5AC5-8CDC-46D4-969D-1245A6880215} - {05248A38-0F34-4E59-A3D1-B07097987AFB} = {CE64E92B-E088-46FB-9028-7FB6B67DEC55} - {12F8343D-20A6-4E24-B0F5-3A66F2228CF6} = {CE64E92B-E088-46FB-9028-7FB6B67DEC55} - {294D6FF8-9379-4AB8-A203-8D0CC85FBFBB} = {05248A38-0F34-4E59-A3D1-B07097987AFB} - {A1D828E4-6B83-4BA2-B8E9-B21CE3BE8A31} = {05248A38-0F34-4E59-A3D1-B07097987AFB} - {86BD3DF6-A3E9-4839-8036-813A20DC8AD6} = {CE64E92B-E088-46FB-9028-7FB6B67DEC55} - {ECCEA352-8953-49D6-8F87-8AB361499420} = {12F8343D-20A6-4E24-B0F5-3A66F2228CF6} - {D64AD07C-A711-42D8-8653-EDCD7A825A44} = {12F8343D-20A6-4E24-B0F5-3A66F2228CF6} - {B3866EEF-8F46-4302-ABAC-A95EE2F27331} = {79981A5A-207A-4A16-A21B-5E80394082F6} - {8C7DAF8E-F792-4092-8BBF-31A6B898B39A} = {93324D12-DE1B-4C1B-934A-92AA140FF6F6} - {B15705B5-041C-4F1E-8342-AD03182EDD42} = {93324D12-DE1B-4C1B-934A-92AA140FF6F6} - {89FE1C3B-29D3-48A8-8E7D-90C261D266C5} = {93324D12-DE1B-4C1B-934A-92AA140FF6F6} - {BCE4A428-8B97-4B56-AE45-496EE3906667} = {2B1F75CE-07A6-4C19-A2E3-F9E062CFDDFB} - {27BEF279-AE73-43DC-92A9-FD7021A999D0} = {2B1F75CE-07A6-4C19-A2E3-F9E062CFDDFB} - {34359707-CE66-4DF0-9EF4-D7544B615564} = {2B1F75CE-07A6-4C19-A2E3-F9E062CFDDFB} - {990CA37A-86D3-4FE6-B777-3CF0DDAC6BF6} = {D36E77BC-4568-4BC8-9506-1EFB7B1CD335} - {2119CE89-308D-4932-BFCE-8CDC0A05EB9E} = {D36E77BC-4568-4BC8-9506-1EFB7B1CD335} - {FE1B1E84-F993-4840-9CAB-9082EB523FDD} = {CE64E92B-E088-46FB-9028-7FB6B67DEC55} - {F17769D7-0E41-4E80-BDD4-282EBE7B5199} = {FE1B1E84-F993-4840-9CAB-9082EB523FDD} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {EA8248C2-3877-4AF7-8777-A17E7881E030} - EndGlobalSection -EndGlobal diff --git a/src/GetToken.http b/src/GetToken.http deleted file mode 100644 index 0de6481c7..000000000 --- a/src/GetToken.http +++ /dev/null @@ -1,10 +0,0 @@ -@Host = https://localhost:7000 - -POST {{Host}}/api/token/ -Accept: application/json -Content-Type: application/json -tenant: root -{ - "email":"admin@root.com", - "password":"123Pa$$word!" -} diff --git a/src/framework/.editorconfig b/src/framework/.editorconfig new file mode 100644 index 000000000..093cab862 --- /dev/null +++ b/src/framework/.editorconfig @@ -0,0 +1,288 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Code Actions #### + +# Type members +dotnet_hide_advanced_members = false +dotnet_member_insertion_location = with_other_members_of_the_same_kind +dotnet_property_generation_behavior = prefer_throwing_properties + +# Symbol search +dotnet_search_reference_assemblies = true + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:suggestion +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:suggestion +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_prefer_system_hash_code = true +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true:error +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:error + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:none +csharp_style_expression_bodied_local_functions = true:error +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_anonymous_function = true +csharp_prefer_static_local_function = true:error +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async +csharp_style_prefer_readonly_struct = true +csharp_style_prefer_readonly_struct_member = true + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:error +csharp_prefer_system_threading_lock = true:suggestion +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_top_level_statements = true:silent + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true:silent +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true:silent +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:error + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### 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, 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 = + +# Naming styles + +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_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 + +# Static code analysis rule customizations + +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = none + +# CA1515: Consider making public types internal +dotnet_diagnostic.CA1515.severity = none + +# CA1724: Type name conflicts with namespace +dotnet_diagnostic.CA1724.severity = none + +# S2094: Classes should not be empty +dotnet_diagnostic.S2094.severity = none + +# IDE0058: Expression value is never used +dotnet_diagnostic.IDE0058.severity = none + +# IDE0005: Remove unnecessary usings/imports +dotnet_diagnostic.IDE0005.severity = none + +# CA1062: Validate arguments of public methods +dotnet_diagnostic.CA1062.severity = none + +# S125: Remove commented out code +dotnet_diagnostic.S125.severity = none + +# IDE0053: Use expression body for lambda expression +dotnet_diagnostic.IDE0053.severity = none + +# IDE0130: Namespace should match project structure +dotnet_diagnostic.IDE0130.severity = none + +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +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_diagnostic.CA1034.severity = none \ No newline at end of file diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs index 28ef66186..3975190a1 100644 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs @@ -1,5 +1,7 @@ -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -using FluentValidation; +using FluentValidation; + +namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; + public static partial class GetUserTrails { public sealed class Validator : AbstractValidator diff --git a/src/framework/Directory.Build.props b/src/framework/Directory.Build.props new file mode 100644 index 000000000..d6449ac52 --- /dev/null +++ b/src/framework/Directory.Build.props @@ -0,0 +1,36 @@ + + + + net9.0 + + + latest + enable + enable + + + true + true + true + latest + AllEnabledByDefault + + + true + 1591 + + + 3.0.0-alpha;latest + + + true + + + + + + all + runtime; build; native; contentfiles; analyzers + + + diff --git a/src/Directory.Packages.props b/src/framework/Directory.Packages.props similarity index 95% rename from src/Directory.Packages.props rename to src/framework/Directory.Packages.props index 8a84537f4..94ddcd2f8 100644 --- a/src/Directory.Packages.props +++ b/src/framework/Directory.Packages.props @@ -9,7 +9,7 @@ true - + @@ -43,7 +43,7 @@ - + @@ -58,12 +58,10 @@ - + - - diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 702750c03..a4d9e3a8b 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -39,6 +39,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{02EA EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Contracts", "Auditing\Auditing.Contracts\Auditing.Contracts.csproj", "{7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/src/framework/Infrastructure/Storage/LocalStorageService.cs b/src/framework/Infrastructure/Storage/LocalStorageService.cs index ab1c98025..7b710874e 100644 --- a/src/framework/Infrastructure/Storage/LocalStorageService.cs +++ b/src/framework/Infrastructure/Storage/LocalStorageService.cs @@ -1,6 +1,7 @@ -namespace FSH.Framework.Infrastructure.Storage; +using FSH.Framework.Core.Storage; using System.Text.RegularExpressions; -using FSH.Framework.Core.Storage; + +namespace FSH.Framework.Infrastructure.Storage; public class LocalStorageService : IStorageService { diff --git a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj index 13aa09383..fb3751384 100644 --- a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj +++ b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj @@ -10,7 +10,6 @@ - diff --git a/src/global.json b/src/global.json index d5bf446d0..01fa100de 100644 --- a/src/global.json +++ b/src/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100", + "version": "9.0.203", "rollForward": "latestFeature" } } \ No newline at end of file From a1b661ea808244bd303777567896f4cfcdb06f1e Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 9 Apr 2025 23:44:30 +0530 Subject: [PATCH 18/54] cleanup csproj --- src/framework/.editorconfig | 6 +++++- src/framework/Application/Application.csproj | 5 ----- .../Auditing/Auditing.Contracts/Auditing.Contracts.csproj | 7 ------- src/framework/Auditing/Auditing.Core/Auditing.Core.csproj | 6 ------ .../Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj | 6 ------ .../Auditing.Infrastructure/Auditing.Infrastructure.csproj | 5 ----- src/framework/Identity/Identity.Core/Identity.Core.csproj | 6 ------ .../Identity/Identity.Endpoints/Identity.Endpoints.csproj | 5 ----- .../Identity.Infrastructure/Identity.Infrastructure.csproj | 5 ----- src/framework/Shared/Shared.csproj | 5 ----- src/framework/Tenant/Tenant.Core/Tenant.Core.csproj | 5 ----- .../Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj | 5 ----- .../Tenant.Infrastructure/Tenant.Infrastructure.csproj | 5 ----- 13 files changed, 5 insertions(+), 66 deletions(-) diff --git a/src/framework/.editorconfig b/src/framework/.editorconfig index 093cab862..9e5ca969b 100644 --- a/src/framework/.editorconfig +++ b/src/framework/.editorconfig @@ -285,4 +285,8 @@ 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_diagnostic.CA1034.severity = none \ No newline at end of file +dotnet_diagnostic.CA1034.severity = none +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 \ No newline at end of file diff --git a/src/framework/Application/Application.csproj b/src/framework/Application/Application.csproj index 638eba449..bf8a4ab17 100644 --- a/src/framework/Application/Application.csproj +++ b/src/framework/Application/Application.csproj @@ -3,11 +3,6 @@ FSH.Framework.Application FSH.Framework.Application - - net9.0 - enable - enable - diff --git a/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj b/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj index 3582910e3..26b279a6b 100644 --- a/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj +++ b/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj @@ -3,14 +3,7 @@ FSH.Framework.Auditing.Contracts FSH.Framework.Auditing.Contracts - - net9.0 - enable - enable - - - diff --git a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj index 9a4dcd97b..de35dbc71 100644 --- a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj +++ b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj @@ -3,11 +3,6 @@ FSH.Framework.Auditing.Core FSH.Framework.Auditing.Core - - net9.0 - enable - enable - @@ -15,5 +10,4 @@ - diff --git a/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj b/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj index aaaf8dbb5..bcdbf7784 100644 --- a/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj +++ b/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj @@ -3,12 +3,6 @@ FSH.Framework.Auditing.Endpoints FSH.Framework.Auditing.Endpoints - - - net9.0 - enable - enable - diff --git a/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj b/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj index bcbddd273..b25bae7b5 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj +++ b/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj @@ -3,11 +3,6 @@ FSH.Framework.Auditing.Infrastructure FSH.Framework.Auditing.Infrastructure - - net9.0 - enable - enable - diff --git a/src/framework/Identity/Identity.Core/Identity.Core.csproj b/src/framework/Identity/Identity.Core/Identity.Core.csproj index 6cc091ce7..d837ed222 100644 --- a/src/framework/Identity/Identity.Core/Identity.Core.csproj +++ b/src/framework/Identity/Identity.Core/Identity.Core.csproj @@ -3,10 +3,4 @@ FSH.Framework.Identity.Core FSH.Framework.Identity.Core - - net9.0 - enable - enable - - diff --git a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj index 2bb99b80b..587355065 100644 --- a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj +++ b/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj @@ -3,11 +3,6 @@ FSH.Framework.Identity.Endpoints FSH.Framework.Identity.Endpoints - - net9.0 - enable - enable - diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index 6148daf12..31a418ff5 100644 --- a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -3,11 +3,6 @@ FSH.Framework.Identity.Infrastructure FSH.Framework.Identity.Infrastructure - - net9.0 - enable - enable - diff --git a/src/framework/Shared/Shared.csproj b/src/framework/Shared/Shared.csproj index e94022f4f..b56774d74 100644 --- a/src/framework/Shared/Shared.csproj +++ b/src/framework/Shared/Shared.csproj @@ -3,11 +3,6 @@ FSH.Framework.Shared FSH.Framework.Shared - - net9.0 - enable - enable - diff --git a/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj b/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj index e1aee7da2..5c4f65e91 100644 --- a/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj +++ b/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj @@ -3,11 +3,6 @@ FSH.Framework.Tenant.Core FSH.Framework.Tenant.Core - - net9.0 - enable - enable - diff --git a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj index fb3751384..d59b779dc 100644 --- a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj +++ b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj @@ -3,11 +3,6 @@ FSH.Framework.Tenant.Endpoints FSH.Framework.Tenant.Endpoints - - net9.0 - enable - enable - diff --git a/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj b/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj index 7774cd70c..5ededb759 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj +++ b/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj @@ -3,11 +3,6 @@ FSH.Framework.Tenant.Infrastructure FSH.Framework.Tenant.Infrastructure - - net9.0 - enable - enable - From 233992592c9e63bb512f1814c0876aacf559bf9b Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 10 Apr 2025 00:21:25 +0530 Subject: [PATCH 19/54] cleanup --- src/framework/.editorconfig | 3 +- .../Auditing/Auditing.Contracts/Trail.cs | 63 +++++++++++++++---- .../Auditing.Endpoints/AuditingModule.cs | 22 +++---- .../Data/AuditingConfiguration.cs | 2 +- .../Data/AuditingDbContext.cs | 4 +- .../Handlers/AuditPublishedEventHandler.cs | 13 ++-- .../Interceptors/AuditInterceptor.cs | 23 +++---- .../Services/AuditService.cs | 4 +- src/framework/Core/Core.csproj | 1 + src/framework/Core/Modules/ICoreModule.cs | 9 +++ src/framework/Directory.Packages.props | 1 + .../Infrastructure/Modules/IEndpointModule.cs | 8 +++ 12 files changed, 108 insertions(+), 45 deletions(-) create mode 100644 src/framework/Core/Modules/ICoreModule.cs create mode 100644 src/framework/Infrastructure/Modules/IEndpointModule.cs diff --git a/src/framework/.editorconfig b/src/framework/.editorconfig index 9e5ca969b..63e88a422 100644 --- a/src/framework/.editorconfig +++ b/src/framework/.editorconfig @@ -289,4 +289,5 @@ dotnet_diagnostic.CA1034.severity = none 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 \ No newline at end of file +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_diagnostic.CA1711.severity = none \ No newline at end of file diff --git a/src/framework/Auditing/Auditing.Contracts/Trail.cs b/src/framework/Auditing/Auditing.Contracts/Trail.cs index fd550b973..9b75c7f7b 100644 --- a/src/framework/Auditing/Auditing.Contracts/Trail.cs +++ b/src/framework/Auditing/Auditing.Contracts/Trail.cs @@ -1,7 +1,7 @@ -using System.Collections.ObjectModel; +using FSH.Framework.Auditing.Contracts.Enums; +using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json; -using FSH.Framework.Auditing.Contracts.Enums; namespace FSH.Framework.Auditing.Contracts; @@ -35,21 +35,62 @@ public class Trail set => KeyValuesJson = JsonSerializer.Serialize(value); } - public Dictionary OldValues + [NotMapped] + public IReadOnlyDictionary OldValues => + JsonSerializer.Deserialize>(OldValuesJson) + ?? new Dictionary(); + + public void SetOldValues(Dictionary values) => + OldValuesJson = JsonSerializer.Serialize(values); + public void SetOldValue(string key, object? value) { - get => JsonSerializer.Deserialize>(OldValuesJson) ?? new Dictionary(); - set => OldValuesJson = JsonSerializer.Serialize(value); + var dict = JsonSerializer.Deserialize>(OldValuesJson) + ?? new Dictionary(); + + dict[key] = value; + + OldValuesJson = JsonSerializer.Serialize(dict); } - public Dictionary NewValues + // --- NewValues --- + + [NotMapped] + public IReadOnlyDictionary NewValues => + JsonSerializer.Deserialize>(NewValuesJson) + ?? new Dictionary(); + + public void SetNewValues(Dictionary values) => + NewValuesJson = JsonSerializer.Serialize(values); + + public void SetNewValue(string key, object? value) { - get => JsonSerializer.Deserialize>(NewValuesJson) ?? new Dictionary(); - set => NewValuesJson = JsonSerializer.Serialize(value); + var dict = JsonSerializer.Deserialize>(NewValuesJson) + ?? new Dictionary(); + + dict[key] = value; + + NewValuesJson = JsonSerializer.Serialize(dict); } - public Collection ModifiedProperties + // --- ModifiedProperties --- + + [NotMapped] + public IReadOnlyCollection ModifiedProperties => + JsonSerializer.Deserialize>(ModifiedPropertiesJson) + ?? new Collection(); + + public void SetModifiedProperties(Collection values) => + ModifiedPropertiesJson = JsonSerializer.Serialize(values); + + public void AddModifiedProperty(string propertyName) { - get => JsonSerializer.Deserialize>(ModifiedPropertiesJson) ?? new Collection(); - set => ModifiedPropertiesJson = JsonSerializer.Serialize(value); + var list = JsonSerializer.Deserialize>(ModifiedPropertiesJson) + ?? new Collection(); + + if (!list.Contains(propertyName)) + list.Add(propertyName); + + ModifiedPropertiesJson = JsonSerializer.Serialize(list); } + } diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs index 710592a01..71fb6a785 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -1,40 +1,38 @@ -using System.Reflection; -using Asp.Versioning; -using Asp.Versioning.Builder; +using Asp.Versioning; using FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; using FSH.Framework.Infrastructure.Messaging.CQRS; +using FSH.Framework.Infrastructure.Modules; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using System.Reflection; namespace FSH.Framework.Auditing.Endpoints; - -public static class AuditingModule +public class AuditingModule : IEndpointModule { - public static IServiceCollection AddAuditingModule(this IServiceCollection services) + public IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config) { services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); - // Add infrastructure, services, mappings, etc. - + // other registrations return services; } - public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuilder endpoints) + public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) { - ApiVersionSet apiVersionSet = endpoints.NewApiVersionSet() + var apiVersionSet = endpoints.NewApiVersionSet() .HasApiVersion(new ApiVersion(1)) .ReportApiVersions() .Build(); - RouteGroupBuilder group = endpoints + var group = endpoints .MapGroup("api/v{version:apiVersion}/auditing") .WithTags("Auditing") .WithOpenApi() .WithApiVersionSet(apiVersionSet); - // v1 endpoints GetUserTrails.MapEndpoint(group); return endpoints; diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs index 6824a041d..8bace7411 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs @@ -1,5 +1,5 @@ using Finbuckle.MultiTenant; -using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Auditing.Contracts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs index fd13f657a..03260f924 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Core.Abstractions; using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Auditing.Infrastructure.Data; diff --git a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs index 6f6525489..6f9101a4f 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs @@ -1,17 +1,20 @@ -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Auditing.Core.Events; -using MediatR; +using FSH.Framework.Auditing.Contracts.Events; +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Core.Messaging.Events; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using System.Diagnostics.CodeAnalysis; namespace FSH.Framework.Auditing.Infrastructure.Handlers; +[SuppressMessage("Performance", "CA1848")] +[SuppressMessage("Design", "CA1031")] public class AuditPublishedEventHandler( ILogger logger, IAuditingDbContext context) - : INotificationHandler + : IEventHandler { - public async Task Handle(AuditPublishedEvent notification, CancellationToken cancellationToken) + public async Task HandleAsync(AuditPublishedEvent notification, CancellationToken cancellationToken = default) { if (notification.Trails == null || notification.Trails.Count == 0) { diff --git a/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs b/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs index 9f5dd80ba..199b14e83 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Auditing.Core.Dtos; -using FSH.Framework.Auditing.Core.Enums; -using FSH.Framework.Auditing.Core.Events; +using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Contracts.Enums; +using FSH.Framework.Auditing.Contracts.Events; using FSH.Framework.Core.Domain; using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.ExecutionContext; @@ -42,6 +42,7 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData, Cancell { Id = Guid.NewGuid(), EntityName = entry.Entity.GetType().Name, + Description = entry.Entity.GetType().Name, UserId = userId, DateTime = utcNow }; @@ -63,12 +64,12 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData, Cancell { case EntityState.Added: audit.Operation = AuditOperation.Create; - audit.NewValues[propertyName] = property.CurrentValue; + audit.SetNewValue(propertyName, property.CurrentValue); break; case EntityState.Deleted: audit.Operation = AuditOperation.Delete; - audit.OldValues[propertyName] = property.OriginalValue; + audit.SetOldValue(propertyName, property.OriginalValue); break; case EntityState.Modified: @@ -76,17 +77,17 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData, Cancell { if (entry.Entity is ISoftDeletable && property.OriginalValue == null && property.CurrentValue != null) { - audit.ModifiedProperties.Add(propertyName); + audit.AddModifiedProperty(propertyName); audit.Operation = AuditOperation.Delete; - audit.OldValues[propertyName] = property.OriginalValue; - audit.NewValues[propertyName] = property.CurrentValue; + audit.SetOldValue(propertyName, property.OriginalValue); + audit.SetNewValue(propertyName, property.CurrentValue); } else if (property.OriginalValue?.Equals(property.CurrentValue) == false) { - audit.ModifiedProperties.Add(propertyName); + audit.AddModifiedProperty(propertyName); audit.Operation = AuditOperation.Update; - audit.OldValues[propertyName] = property.OriginalValue; - audit.NewValues[propertyName] = property.CurrentValue; + audit.SetOldValue(propertyName, property.OriginalValue); + audit.SetNewValue(propertyName, property.CurrentValue); } else { diff --git a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs index b015065d3..a4f285960 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs +++ b/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Auditing.Core.Dtos; +using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Core.Abstractions; using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Auditing.Infrastructure.Services; diff --git a/src/framework/Core/Core.csproj b/src/framework/Core/Core.csproj index e97b22185..4761a6bb8 100644 --- a/src/framework/Core/Core.csproj +++ b/src/framework/Core/Core.csproj @@ -6,6 +6,7 @@ + diff --git a/src/framework/Core/Modules/ICoreModule.cs b/src/framework/Core/Modules/ICoreModule.cs new file mode 100644 index 000000000..9b693915e --- /dev/null +++ b/src/framework/Core/Modules/ICoreModule.cs @@ -0,0 +1,9 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Core.Modules; + +public interface ICoreModule +{ + IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config); +} diff --git a/src/framework/Directory.Packages.props b/src/framework/Directory.Packages.props index 94ddcd2f8..3b0367faf 100644 --- a/src/framework/Directory.Packages.props +++ b/src/framework/Directory.Packages.props @@ -30,6 +30,7 @@ + diff --git a/src/framework/Infrastructure/Modules/IEndpointModule.cs b/src/framework/Infrastructure/Modules/IEndpointModule.cs new file mode 100644 index 000000000..a88637ddf --- /dev/null +++ b/src/framework/Infrastructure/Modules/IEndpointModule.cs @@ -0,0 +1,8 @@ +using FSH.Framework.Core.Modules; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Infrastructure.Modules; +public interface IEndpointModule : ICoreModule +{ + IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints); +} \ No newline at end of file From d2daa9fa6ba6b4dad5e1d099a8a5144dd5e0bfc6 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 10 Apr 2025 02:02:36 +0530 Subject: [PATCH 20/54] stash --- src/framework/.editorconfig | 2 +- .../ActivateTenant/ActivateTenantHandler.cs | 5 +-- .../Activate/ActivateTenantCommand.cs | 4 -- .../Activate/ActivateTenantResponse.cs | 2 - .../Tenant.Endpoints/Tenant.Endpoints.csproj | 6 +++ .../Tenant/Tenant.Endpoints/TenantModule.cs | 40 +++++++++++++++++++ .../v1/Activate/ActivateTenant.Command.cs | 7 ++++ .../v1/Activate/ActivateTenant.Endpoint.cs | 19 +++++++++ .../v1/Activate/ActivateTenant.Handler.cs | 16 ++++++++ .../v1/Activate/ActivateTenant.Response.cs | 5 +++ .../v1/Activate/ActivateTenant.Validator.cs | 13 ++++++ .../v1/Activate/ActivateTenantEndpoint.cs | 17 -------- .../v1/CreateTenantEndpoint.cs | 19 --------- .../v1/GetTenantByIdEndpoint.cs | 5 +-- 14 files changed, 110 insertions(+), 50 deletions(-) delete mode 100644 src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs delete mode 100644 src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/TenantModule.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenantEndpoint.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/CreateTenantEndpoint.cs diff --git a/src/framework/.editorconfig b/src/framework/.editorconfig index 63e88a422..121f35bc7 100644 --- a/src/framework/.editorconfig +++ b/src/framework/.editorconfig @@ -124,7 +124,7 @@ csharp_style_prefer_readonly_struct_member = true csharp_prefer_braces = true:silent csharp_prefer_simple_using_statement = true:error csharp_prefer_system_threading_lock = true:suggestion -csharp_style_namespace_declarations = file_scoped:silent +csharp_style_namespace_declarations = file_scoped:error csharp_style_prefer_method_group_conversion = true:silent csharp_style_prefer_primary_constructors = true:suggestion csharp_style_prefer_top_level_statements = true:silent diff --git a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs index ab018e532..8c932484c 100644 --- a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs +++ b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs @@ -1,7 +1,4 @@ -using FSH.Framework.Core.Tenant.Abstractions; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.ActivateTenant; +namespace FSH.Framework.Core.Tenant.Features.ActivateTenant; public sealed class ActivateTenantHandler(ITenantService service) : IRequestHandler { public async Task Handle(ActivateTenantCommand request, CancellationToken cancellationToken) diff --git a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs deleted file mode 100644 index daaa872cb..000000000 --- a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantCommand.cs +++ /dev/null @@ -1,4 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; - -namespace FSH.Framework.Tenant.Core.Features.Activate; -public record ActivateTenantCommand(string TenantId) : ICommand; diff --git a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs b/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs deleted file mode 100644 index c89a2bcb3..000000000 --- a/src/framework/Tenant/Tenant.Core/Features/Activate/ActivateTenantResponse.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Tenant.Core.Features.Activate; -public record ActivateTenantResponse(string Status); diff --git a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj index d59b779dc..526fd1b38 100644 --- a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj +++ b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj @@ -9,4 +9,10 @@ + + + + + + diff --git a/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs b/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs new file mode 100644 index 000000000..9e1501904 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs @@ -0,0 +1,40 @@ +using Asp.Versioning; +using FSH.Framework.Infrastructure.Messaging.CQRS; +using FSH.Framework.Infrastructure.Modules; +using FSH.Framework.Tenant.Endpoints.v1.Activate; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; + +namespace FSH.Framework.Tenant.Endpoints; +public class TenantModule : IEndpointModule +{ + public IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config) + { + services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); + + // other registrations + return services; + } + + public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) + { + var apiVersionSet = endpoints.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1)) + .ReportApiVersions() + .Build(); + + var group = endpoints + .MapGroup("api/v{version:apiVersion}/tenants") + .WithTags("Tenants") + .WithOpenApi() + .WithApiVersionSet(apiVersionSet); + + ActivateTenant.MapEndpoint(group); + + return endpoints; + } +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs new file mode 100644 index 000000000..fe37f3ac1 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs @@ -0,0 +1,7 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Tenant.Endpoints.v1.Activate; +public static partial class ActivateTenant +{ + public sealed record Command(string TenantId) : ICommand; +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs new file mode 100644 index 000000000..e65d04d06 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs @@ -0,0 +1,19 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Endpoints.v1.Activate; +public static partial class ActivateTenant +{ + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/{id}/activate", async (ICommandDispatcher dispatcher, string id) + => await dispatcher.SendAsync(new Command(id))) + .WithName(nameof(ActivateTenant)) + .WithSummary("activate tenant") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("activate tenant"); + } +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs new file mode 100644 index 000000000..50c1c984d --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs @@ -0,0 +1,16 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Core.Abstractions; + +namespace FSH.Framework.Tenant.Endpoints.v1.Activate; +public static partial class ActivateTenant +{ + public sealed class Handler(ITenantService tenantService) : ICommandHandler + { + public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) + { + var result = await tenantService.ActivateAsync(command.TenantId, cancellationToken); + return new Response(result); + } + } +} + diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs new file mode 100644 index 000000000..5152598fa --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Tenant.Endpoints.v1.Activate; +public static partial class ActivateTenant +{ + public record Response(string Status); +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs new file mode 100644 index 000000000..024be6e91 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs @@ -0,0 +1,13 @@ +using FluentValidation; + +namespace FSH.Framework.Tenant.Endpoints.v1.Activate; +public static partial class ActivateTenant +{ + public sealed class Validator : AbstractValidator + { + public Validator() => + RuleFor(t => t.TenantId) + .NotEmpty(); + } + +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenantEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenantEndpoint.cs deleted file mode 100644 index 0160b5690..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenantEndpoint.cs +++ /dev/null @@ -1,17 +0,0 @@ -using MediatR; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Endpoints.v1.Activate; -public static class ActivateTenantEndpoint -{ - internal static RouteHandlerBuilder MapActivateTenantEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/{id}/activate", (ISender mediator, string id) => mediator.Send(new ActivateTenantCommand(id))) - .WithName(nameof(ActivateTenantEndpoint)) - .WithSummary("activate tenant") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("activate tenant"); - } -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenantEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenantEndpoint.cs deleted file mode 100644 index 51d8a9f6f..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenantEndpoint.cs +++ /dev/null @@ -1,19 +0,0 @@ -using FSH.Framework.Core.Tenant.Features.CreateTenant; -using FSH.Framework.Infrastructure.Auth.Policy; -using MediatR; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; -public static class CreateTenantEndpoint -{ - internal static RouteHandlerBuilder MapRegisterTenantEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/", (CreateTenantCommand request, ISender mediator) => mediator.Send(request)) - .WithName(nameof(CreateTenantEndpoint)) - .WithSummary("creates a tenant") - .RequirePermission("Permissions.Tenants.Create") - .WithDescription("creates a tenant"); - } -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs index a429ac62e..ab4591269 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs +++ b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs @@ -1,6 +1,4 @@ using FSH.Framework.Core.Tenant.Features.GetTenantById; -using FSH.Framework.Infrastructure.Auth.Policy; -using MediatR; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -10,7 +8,8 @@ public static class GetTenantByIdEndpoint { internal static RouteHandlerBuilder MapGetTenantByIdEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapGet("/{id}", (ISender mediator, string id) => mediator.Send(new GetTenantByIdQuery(id))) + return endpoints.MapGet("/{id}", (ISender mediator, string id) + => mediator.Send(new GetTenantByIdQuery(id))) .WithName(nameof(GetTenantByIdEndpoint)) .WithSummary("get tenant by id") .RequirePermission("Permissions.Tenants.View") From 5c6ad2b97c08d68fac6b68df3f447ffd4bbeb9d3 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 10 Apr 2025 18:33:30 +0530 Subject: [PATCH 21/54] upgrade tenant handlers --- .../ActivateTenant/ActivateTenantHandler.cs | 9 --- .../ActivateTenant/ActivateTenantValidator.cs | 9 --- .../CreateTenant/CreateTenantCommand.cs | 8 --- .../CreateTenant/CreateTenantHandler.cs | 12 ---- .../CreateTenant/CreateTenantResponse.cs | 2 - .../CreateTenant/CreateTenantValidator.cs | 30 --------- .../DisableTenant/DisableTenantCommand.cs | 4 -- .../DisableTenant/DisableTenantHandler.cs | 12 ---- .../DisableTenant/DisableTenantResponse.cs | 2 - .../DisableTenant/DisableTenantValidator.cs | 9 --- .../GetTenantById/GetTenantByIdHandler.cs | 12 ---- .../GetTenantById/GetTenantByIdQuery.cs | 5 -- .../Features/GetTenants/GetTenantsHandler.cs | 12 ---- .../Features/GetTenants/GetTenantsQuery.cs | 5 -- .../UpgradeSubscriptionCommand.cs | 8 --- .../UpgradeSubscriptionHandler.cs | 17 ----- .../UpgradeSubscriptionResponse.cs | 2 - .../UpgradeSubscriptionValidator.cs | 11 ---- .../Tokens/Generate/TokenGenerationCommand.cs | 5 -- .../Generate/TokenGenerationEndpoint.cs | 26 -------- .../Tokens/Generate/TokenGenerationHandler.cs | 21 ------- .../Generate/TokenGenerationResponse.cs | 5 -- .../Generate/TokenGenerationValidator.cs | 17 ----- .../v1/Tokens/Refresh/RefreshTokenEndpoint.cs | 26 -------- .../Refresh/TokenRefreshRequestValidator.cs | 13 ---- .../v1/Tokens/RefreshToken.cs | 48 ++++++++++++++ .../v1/Tokens/TokenGeneration.cs | 56 +++++++++++++++++ .../Abstractions/ITenantService.cs | 6 +- .../Tenant.Core}/TenantDetail.cs | 2 +- .../Tenant/Tenant.Endpoints/TenantModule.cs | 8 ++- .../v1/Activate/ActivateTenant.Command.cs | 7 --- .../v1/Activate/ActivateTenant.Endpoint.cs | 19 ------ .../v1/Activate/ActivateTenant.Handler.cs | 16 ----- .../v1/Activate/ActivateTenant.Response.cs | 5 -- .../v1/Activate/ActivateTenant.Validator.cs | 13 ---- .../Tenant.Endpoints/v1/ActivateTenant.cs | 37 +++++++++++ .../Tenant.Endpoints/v1/CreateTenant.cs | 62 +++++++++++++++++++ .../Tenant.Endpoints/v1/DisableTenant.cs | 38 ++++++++++++ .../v1/DisableTenantEndpoint.cs | 19 ------ .../Tenant/Tenant.Endpoints/v1/Extensions.cs | 20 ------ .../Tenant.Endpoints/v1/GetTenantById.cs | 49 +++++++++++++++ .../v1/GetTenantByIdEndpoint.cs | 18 ------ .../Tenant/Tenant.Endpoints/v1/GetTenants.cs | 38 ++++++++++++ .../Tenant.Endpoints/v1/GetTenantsEndpoint.cs | 19 ------ .../v1/UpgradeSubscription.cs | 42 +++++++++++++ .../v1/UpgradeSubscriptionEndpoint.cs | 20 ------ .../Tenant.Infrastructure/TenantService.cs | 2 +- 47 files changed, 383 insertions(+), 443 deletions(-) delete mode 100644 src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs delete mode 100644 src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs delete mode 100644 src/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs delete mode 100644 src/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs delete mode 100644 src/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs delete mode 100644 src/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs delete mode 100644 src/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs delete mode 100644 src/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs delete mode 100644 src/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs delete mode 100644 src/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs delete mode 100644 src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs delete mode 100644 src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs delete mode 100644 src/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs delete mode 100644 src/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs delete mode 100644 src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs delete mode 100644 src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs delete mode 100644 src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs delete mode 100644 src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs create mode 100644 src/framework/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs rename src/framework/{Core/Tenant/Dtos => Tenant/Tenant.Core}/TenantDetail.cs (88%) delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/ActivateTenant.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/DisableTenant.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/DisableTenantEndpoint.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/Extensions.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/GetTenantById.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/GetTenants.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/GetTenantsEndpoint.cs create mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscription.cs delete mode 100644 src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscriptionEndpoint.cs diff --git a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs deleted file mode 100644 index 8c932484c..000000000 --- a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace FSH.Framework.Core.Tenant.Features.ActivateTenant; -public sealed class ActivateTenantHandler(ITenantService service) : IRequestHandler -{ - public async Task Handle(ActivateTenantCommand request, CancellationToken cancellationToken) - { - var status = await service.ActivateAsync(request.TenantId, cancellationToken); - return new ActivateTenantResponse(status); - } -} diff --git a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs b/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs deleted file mode 100644 index de9bceb45..000000000 --- a/src/framework/Core/Tenant/Features/ActivateTenant/ActivateTenantValidator.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Core.Tenant.Features.ActivateTenant; -public sealed class ActivateTenantValidator : AbstractValidator -{ - public ActivateTenantValidator() => - RuleFor(t => t.TenantId) - .NotEmpty(); -} diff --git a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs deleted file mode 100644 index a6bec8593..000000000 --- a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantCommand.cs +++ /dev/null @@ -1,8 +0,0 @@ -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.CreateTenant; -public sealed record CreateTenantCommand(string Id, - string Name, - string? ConnectionString, - string AdminEmail, - string? Issuer) : IRequest; diff --git a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs deleted file mode 100644 index d948367cb..000000000 --- a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -using FSH.Framework.Core.Tenant.Abstractions; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.CreateTenant; -public sealed class CreateTenantHandler(ITenantService service) : IRequestHandler -{ - public async Task Handle(CreateTenantCommand request, CancellationToken cancellationToken) - { - var tenantId = await service.CreateAsync(request, cancellationToken); - return new CreateTenantResponse(tenantId); - } -} diff --git a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs deleted file mode 100644 index 7a778e4f7..000000000 --- a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantResponse.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Core.Tenant.Features.CreateTenant; -public record CreateTenantResponse(string Id); diff --git a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs b/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs deleted file mode 100644 index 16e9816af..000000000 --- a/src/framework/Core/Tenant/Features/CreateTenant/CreateTenantValidator.cs +++ /dev/null @@ -1,30 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Persistence; -using FSH.Framework.Core.Tenant.Abstractions; - -namespace FSH.Framework.Core.Tenant.Features.CreateTenant; -public class CreateTenantValidator : AbstractValidator -{ - public CreateTenantValidator( - ITenantService tenantService, - IConnectionStringValidator connectionStringValidator) - { - RuleFor(t => t.Id).Cascade(CascadeMode.Stop) - .NotEmpty() - .MustAsync(async (id, _) => !await tenantService.ExistsWithIdAsync(id).ConfigureAwait(false)) - .WithMessage((_, id) => $"Tenant {id} already exists."); - - RuleFor(t => t.Name).Cascade(CascadeMode.Stop) - .NotEmpty() - .MustAsync(async (name, _) => !await tenantService.ExistsWithNameAsync(name!).ConfigureAwait(false)) - .WithMessage((_, name) => $"Tenant {name} already exists."); - - RuleFor(t => t.ConnectionString).Cascade(CascadeMode.Stop) - .Must((_, cs) => string.IsNullOrWhiteSpace(cs) || connectionStringValidator.TryValidate(cs)) - .WithMessage("Connection string invalid."); - - RuleFor(t => t.AdminEmail).Cascade(CascadeMode.Stop) - .NotEmpty() - .EmailAddress(); - } -} diff --git a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs deleted file mode 100644 index bc0dc1fa9..000000000 --- a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantCommand.cs +++ /dev/null @@ -1,4 +0,0 @@ -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.DisableTenant; -public record DisableTenantCommand(string TenantId) : IRequest; diff --git a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs deleted file mode 100644 index d9cad8dcb..000000000 --- a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -using FSH.Framework.Core.Tenant.Abstractions; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.DisableTenant; -public sealed class DisableTenantHandler(ITenantService service) : IRequestHandler -{ - public async Task Handle(DisableTenantCommand request, CancellationToken cancellationToken) - { - var status = await service.DeactivateAsync(request.TenantId); - return new DisableTenantResponse(status); - } -} diff --git a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs deleted file mode 100644 index 89ce0c053..000000000 --- a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantResponse.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Core.Tenant.Features.DisableTenant; -public record DisableTenantResponse(string Status); diff --git a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs b/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs deleted file mode 100644 index 2c0831e20..000000000 --- a/src/framework/Core/Tenant/Features/DisableTenant/DisableTenantValidator.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Core.Tenant.Features.DisableTenant; -public sealed class DisableTenantValidator : AbstractValidator -{ - public DisableTenantValidator() => - RuleFor(t => t.TenantId) - .NotEmpty(); -} diff --git a/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs b/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs deleted file mode 100644 index ec8e68737..000000000 --- a/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -using FSH.Framework.Core.Tenant.Abstractions; -using FSH.Framework.Core.Tenant.Dtos; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.GetTenantById; -public sealed class GetTenantByIdHandler(ITenantService service) : IRequestHandler -{ - public async Task Handle(GetTenantByIdQuery request, CancellationToken cancellationToken) - { - return await service.GetByIdAsync(request.TenantId); - } -} diff --git a/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs b/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs deleted file mode 100644 index 9f75bc68c..000000000 --- a/src/framework/Core/Tenant/Features/GetTenantById/GetTenantByIdQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using FSH.Framework.Core.Tenant.Dtos; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.GetTenantById; -public record GetTenantByIdQuery(string TenantId) : IRequest; diff --git a/src/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs b/src/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs deleted file mode 100644 index 1ccd5f90e..000000000 --- a/src/framework/Core/Tenant/Features/GetTenants/GetTenantsHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -using FSH.Framework.Core.Tenant.Abstractions; -using FSH.Framework.Core.Tenant.Dtos; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.GetTenants; -public sealed class GetTenantsHandler(ITenantService service) : IRequestHandler> -{ - public Task> Handle(GetTenantsQuery request, CancellationToken cancellationToken) - { - return service.GetAllAsync(); - } -} diff --git a/src/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs b/src/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs deleted file mode 100644 index dba6bc189..000000000 --- a/src/framework/Core/Tenant/Features/GetTenants/GetTenantsQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using FSH.Framework.Core.Tenant.Dtos; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.GetTenants; -public sealed class GetTenantsQuery : IRequest>; diff --git a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs deleted file mode 100644 index f132f455b..000000000 --- a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionCommand.cs +++ /dev/null @@ -1,8 +0,0 @@ -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.UpgradeSubscription; -public class UpgradeSubscriptionCommand : IRequest -{ - public string Tenant { get; set; } = default!; - public DateTime ExtendedExpiryDate { get; set; } -} diff --git a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs deleted file mode 100644 index e4cbbb4e7..000000000 --- a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionHandler.cs +++ /dev/null @@ -1,17 +0,0 @@ -using FSH.Framework.Core.Tenant.Abstractions; -using MediatR; - -namespace FSH.Framework.Core.Tenant.Features.UpgradeSubscription; - -public class UpgradeSubscriptionHandler : IRequestHandler -{ - private readonly ITenantService _tenantService; - - public UpgradeSubscriptionHandler(ITenantService tenantService) => _tenantService = tenantService; - - public async Task Handle(UpgradeSubscriptionCommand request, CancellationToken cancellationToken) - { - var validUpto = await _tenantService.UpgradeSubscription(request.Tenant, request.ExtendedExpiryDate); - return new UpgradeSubscriptionResponse(validUpto, request.Tenant); - } -} diff --git a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs deleted file mode 100644 index ef14487b7..000000000 --- a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionResponse.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Core.Tenant.Features.UpgradeSubscription; -public record UpgradeSubscriptionResponse(DateTime NewValidity, string Tenant); diff --git a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs b/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs deleted file mode 100644 index daddf1fbf..000000000 --- a/src/framework/Core/Tenant/Features/UpgradeSubscription/UpgradeSubscriptionValidator.cs +++ /dev/null @@ -1,11 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Core.Tenant.Features.UpgradeSubscription; -public class UpgradeSubscriptionValidator : AbstractValidator -{ - public UpgradeSubscriptionValidator() - { - RuleFor(t => t.Tenant).NotEmpty(); - RuleFor(t => t.ExtendedExpiryDate).GreaterThan(DateTime.UtcNow); - } -} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs deleted file mode 100644 index e47c97146..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationCommand.cs +++ /dev/null @@ -1,5 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; -public sealed record TokenGenerationCommand(string Email, string Password) - : ICommand; diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs deleted file mode 100644 index 821d5cd3b..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationEndpoint.cs +++ /dev/null @@ -1,26 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; -public static class TokenGenerationEndpoint -{ - internal static RouteHandlerBuilder MapTokenGenerationEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/", async ( - TokenGenerationCommand command, - string tenant, - ICommandDispatcher dispatcher, - HttpContext context, - CancellationToken cancellationToken) => - { - var result = await dispatcher.SendAsync(command, cancellationToken); - return TypedResults.Ok(result); - }) - .WithName("TokenGeneration") - .WithSummary("Generate JWTs") - .WithDescription("Generates access and refresh tokens.") - .AllowAnonymous(); - } -} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs deleted file mode 100644 index bb3d8ddc4..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationHandler.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Core.Tokens; -using FSH.Framework.Shared.Extensions; -using Microsoft.AspNetCore.Http; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; -public sealed class TokenGenerationHandler( - ITokenService tokenService, - HttpContext context) - : ICommandHandler -{ - public async Task HandleAsync(TokenGenerationCommand command, CancellationToken cancellationToken = default) - { - var request = new TokenGenerationRequest(command.Email, command.Password); - string ip = context.GetIpAddress(); - - var token = await tokenService.GenerateTokenAsync(request, ip, cancellationToken); - - return new TokenGenerationResponse(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); - } -} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs deleted file mode 100644 index 2661aa7e3..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationResponse.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; -public sealed record TokenGenerationResponse( - string Token, - string RefreshToken, - DateTime RefreshTokenExpiryTime); diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs deleted file mode 100644 index e55abe7a3..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Generate/TokenGenerationValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Generate; -using FluentValidation; - -public sealed class TokenGenerationValidator : AbstractValidator -{ - public TokenGenerationValidator() - { - RuleFor(p => p.Email) - .Cascade(CascadeMode.Stop) - .NotEmpty() - .EmailAddress(); - - RuleFor(p => p.Password) - .Cascade(CascadeMode.Stop) - .NotEmpty(); - } -} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs deleted file mode 100644 index 47e7b2545..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/RefreshTokenEndpoint.cs +++ /dev/null @@ -1,26 +0,0 @@ -using FSH.Framework.Identity.Core.Tokens; -using FSH.Framework.Shared.Extensions; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Refresh; -public static class RefreshTokenEndpoint -{ - internal static RouteHandlerBuilder MapRefreshTokenEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/refresh", (TokenRefreshRequest request, - string tenant, - ITokenService service, - HttpContext context, - CancellationToken cancellationToken) => - { - string ip = context.GetIpAddress(); - return service.RefreshTokenAsync(request, ip!, cancellationToken); - }) - .WithName(nameof(RefreshTokenEndpoint)) - .WithSummary("refresh JWTs") - .WithDescription("refresh JWTs") - .AllowAnonymous(); - } -} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs deleted file mode 100644 index c1f3d7939..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/Refresh/TokenRefreshRequestValidator.cs +++ /dev/null @@ -1,13 +0,0 @@ -using FluentValidation; -using FSH.Framework.Identity.Core.Tokens; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens.Refresh; -public class TokenRefreshRequestValidator : AbstractValidator -{ - public TokenRefreshRequestValidator() - { - RuleFor(p => p.Token).Cascade(CascadeMode.Stop).NotEmpty(); - - RuleFor(p => p.RefreshToken).Cascade(CascadeMode.Stop).NotEmpty(); - } -} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs new file mode 100644 index 000000000..a73629eb0 --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs @@ -0,0 +1,48 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Shared.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Identity.Endpoints.v1.Tokens; +public static class RefreshToken +{ + public sealed record Command(string Token, string RefreshToken) : ICommand; + public sealed record Response(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); + public class Validator : AbstractValidator + { + public Validator() + { + RuleFor(p => p.Token).Cascade(CascadeMode.Stop).NotEmpty(); + RuleFor(p => p.RefreshToken).Cascade(CascadeMode.Stop).NotEmpty(); + } + } + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/refresh", async (Command command, + string tenant, + ICommandDispatcher dispatcher, + HttpContext context, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync(command, cancellationToken); + return TypedResults.Ok(result); + }) + .WithName(nameof(RefreshToken)) + .WithSummary("refresh JWTs") + .WithDescription("refresh JWTs") + .AllowAnonymous(); + } + public sealed class Handler(ITokenService tokenService, HttpContext context) : ICommandHandler + { + public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) + { + var request = new TokenRefreshRequest(command.Token, command.RefreshToken); + string ip = context.GetIpAddress(); + var token = await tokenService.RefreshTokenAsync(request, ip, cancellationToken); + return new Response(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); + } + } +} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs b/src/framework/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs new file mode 100644 index 000000000..b8081e27e --- /dev/null +++ b/src/framework/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs @@ -0,0 +1,56 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Shared.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Identity.Endpoints.v1.Tokens; +public static class TokenGeneration +{ + public sealed record Command(string Email, string Password) : ICommand; + public sealed record Response(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); + public sealed class Validator : AbstractValidator + { + public Validator() + { + RuleFor(p => p.Email) + .Cascade(CascadeMode.Stop) + .NotEmpty() + .EmailAddress(); + + RuleFor(p => p.Password) + .Cascade(CascadeMode.Stop) + .NotEmpty(); + } + } + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/", async ( + Command command, + string tenant, + ICommandDispatcher dispatcher, + HttpContext context, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync(command, cancellationToken); + return TypedResults.Ok(result); + }) + .WithName(nameof(TokenGeneration)) + .WithSummary("Generate JWTs") + .WithDescription("Generates access and refresh tokens.") + .AllowAnonymous(); + } + + public sealed class Handler(ITokenService tokenService, HttpContext context) : ICommandHandler + { + public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) + { + var request = new TokenGenerationRequest(command.Email, command.Password); + string ip = context.GetIpAddress(); + var token = await tokenService.GenerateTokenAsync(request, ip, cancellationToken); + return new Response(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); + } + } +} diff --git a/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs b/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs index dfae1c2d5..8f5151b03 100644 --- a/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs +++ b/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs @@ -1,4 +1,6 @@ -namespace FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Core.Tenant; + +namespace FSH.Framework.Tenant.Core.Abstractions; public interface ITenantService { @@ -10,7 +12,7 @@ public interface ITenantService Task GetByIdAsync(string id); - Task CreateAsync(CreateTenantCommand request, CancellationToken cancellationToken); + Task CreateAsync(string id, string name, string? connectionString, string adminEmail, string? issuer, CancellationToken cancellationToken); Task ActivateAsync(string id, CancellationToken cancellationToken); diff --git a/src/framework/Core/Tenant/Dtos/TenantDetail.cs b/src/framework/Tenant/Tenant.Core/TenantDetail.cs similarity index 88% rename from src/framework/Core/Tenant/Dtos/TenantDetail.cs rename to src/framework/Tenant/Tenant.Core/TenantDetail.cs index c9e44f8b7..da1ecb726 100644 --- a/src/framework/Core/Tenant/Dtos/TenantDetail.cs +++ b/src/framework/Tenant/Tenant.Core/TenantDetail.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Tenant.Dtos; +namespace FSH.Framework.Core.Tenant; public class TenantDetail { public string Id { get; set; } = default!; diff --git a/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs b/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs index 9e1501904..fe76ae3d3 100644 --- a/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs +++ b/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs @@ -1,7 +1,8 @@ using Asp.Versioning; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Modules; -using FSH.Framework.Tenant.Endpoints.v1.Activate; +using FSH.Framework.Infrastructure.Tenant.Endpoints; +using FSH.Framework.Tenant.Endpoints.v1; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -34,6 +35,11 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) .WithApiVersionSet(apiVersionSet); ActivateTenant.MapEndpoint(group); + CreateTenant.MapEndpoint(group); + DisableTenant.MapEndpoint(group); + GetTenantById.MapEndpoint(group); + GetTenants.MapEndpoint(group); + UpgradeSubscription.MapEndpoint(group); return endpoints; } diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs deleted file mode 100644 index fe37f3ac1..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Command.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; - -namespace FSH.Framework.Tenant.Endpoints.v1.Activate; -public static partial class ActivateTenant -{ - public sealed record Command(string TenantId) : ICommand; -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs deleted file mode 100644 index e65d04d06..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Endpoint.cs +++ /dev/null @@ -1,19 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Endpoints.v1.Activate; -public static partial class ActivateTenant -{ - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/{id}/activate", async (ICommandDispatcher dispatcher, string id) - => await dispatcher.SendAsync(new Command(id))) - .WithName(nameof(ActivateTenant)) - .WithSummary("activate tenant") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("activate tenant"); - } -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs deleted file mode 100644 index 50c1c984d..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Handler.cs +++ /dev/null @@ -1,16 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Tenant.Core.Abstractions; - -namespace FSH.Framework.Tenant.Endpoints.v1.Activate; -public static partial class ActivateTenant -{ - public sealed class Handler(ITenantService tenantService) : ICommandHandler - { - public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) - { - var result = await tenantService.ActivateAsync(command.TenantId, cancellationToken); - return new Response(result); - } - } -} - diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs deleted file mode 100644 index 5152598fa..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Response.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace FSH.Framework.Tenant.Endpoints.v1.Activate; -public static partial class ActivateTenant -{ - public record Response(string Status); -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs deleted file mode 100644 index 024be6e91..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/Activate/ActivateTenant.Validator.cs +++ /dev/null @@ -1,13 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Tenant.Endpoints.v1.Activate; -public static partial class ActivateTenant -{ - public sealed class Validator : AbstractValidator - { - public Validator() => - RuleFor(t => t.TenantId) - .NotEmpty(); - } - -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/ActivateTenant.cs b/src/framework/Tenant/Tenant.Endpoints/v1/ActivateTenant.cs new file mode 100644 index 000000000..2f3ae225e --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/ActivateTenant.cs @@ -0,0 +1,37 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Core.Abstractions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Endpoints.v1; +public static class ActivateTenant +{ + public sealed record Command(string TenantId) : ICommand; + public record Response(string Status); + public sealed class Validator : AbstractValidator + { + public Validator() => + RuleFor(t => t.TenantId) + .NotEmpty(); + } + public sealed class Handler(ITenantService tenantService) : ICommandHandler + { + public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) + { + var result = await tenantService.ActivateAsync(command.TenantId, cancellationToken); + return new Response(result); + } + } + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/{id}/activate", async (ICommandDispatcher dispatcher, string id) + => await dispatcher.SendAsync(new Command(id))) + .WithName(nameof(ActivateTenant)) + .WithSummary("activate tenant") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("activate tenant"); + } +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs b/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs new file mode 100644 index 000000000..4843a3a9f --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs @@ -0,0 +1,62 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Tenant.Endpoints.v1.Activate; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Endpoints.v1; +public static class CreateTenant +{ + public sealed record Command(string Id, string Name, string? ConnectionString, string AdminEmail, string? Issuer) : ICommand; + public sealed record Response(string Id); + public class Validator : AbstractValidator + { + public Validator(ITenantService tenantService, IConnectionStringValidator connectionStringValidator) + { + RuleFor(t => t.Id).Cascade(CascadeMode.Stop) + .NotEmpty() + .MustAsync(async (id, _) => !await tenantService.ExistsWithIdAsync(id).ConfigureAwait(false)) + .WithMessage((_, id) => $"Tenant {id} already exists."); + + RuleFor(t => t.Name).Cascade(CascadeMode.Stop) + .NotEmpty() + .MustAsync(async (name, _) => !await tenantService.ExistsWithNameAsync(name!).ConfigureAwait(false)) + .WithMessage((_, name) => $"Tenant {name} already exists."); + + RuleFor(t => t.ConnectionString).Cascade(CascadeMode.Stop) + .Must((_, cs) => string.IsNullOrWhiteSpace(cs) || connectionStringValidator.TryValidate(cs)) + .WithMessage("Connection string invalid."); + + RuleFor(t => t.AdminEmail).Cascade(CascadeMode.Stop) + .NotEmpty() + .EmailAddress(); + } + } + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/", async (ICommandDispatcher dispatcher, Command command) + => await dispatcher.SendAsync(command)) + .WithName(nameof(ActivateTenant)) + .WithSummary("activate tenant") + .RequirePermission("Permissions.Tenants.Create") + .WithDescription("activate tenant"); + } + public sealed class Handler(ITenantService service) : ICommandHandler + { + public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) + { + var tenantId = await service.CreateAsync(command.Id, + command.Name, + command.ConnectionString, + command.AdminEmail, + command.Issuer, + cancellationToken); + return new Response(tenantId); + } + } + +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenant.cs b/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenant.cs new file mode 100644 index 000000000..b65fb8d84 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenant.cs @@ -0,0 +1,38 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Core.Abstractions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Endpoints.v1; +public static class DisableTenant +{ + public sealed record Command(string TenantId) : ICommand; + public sealed record Response(string Status); + public sealed class DisableTenantValidator : AbstractValidator + { + public DisableTenantValidator() => + RuleFor(t => t.TenantId) + .NotEmpty(); + } + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/{id}/deactivate", (ICommandDispatcher dispatcher, string id) + => dispatcher.SendAsync(new Command(id))) + .WithName(nameof(DisableTenant)) + .WithSummary("activate tenant") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("activate tenant"); + } + public sealed class Handler(ITenantService service) : ICommandHandler + { + public async Task HandleAsync(Command request, CancellationToken cancellationToken = default) + { + var status = await service.DeactivateAsync(request.TenantId); + return new Response(status); + } + } + +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenantEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenantEndpoint.cs deleted file mode 100644 index 64ef61320..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenantEndpoint.cs +++ /dev/null @@ -1,19 +0,0 @@ -using FSH.Framework.Core.Tenant.Features.DisableTenant; -using FSH.Framework.Infrastructure.Auth.Policy; -using MediatR; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; -public static class DisableTenantEndpoint -{ - internal static RouteHandlerBuilder MapDisableTenantEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/{id}/deactivate", (ISender mediator, string id) => mediator.Send(new DisableTenantCommand(id))) - .WithName(nameof(DisableTenantEndpoint)) - .WithSummary("activate tenant") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("activate tenant"); - } -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/Extensions.cs b/src/framework/Tenant/Tenant.Endpoints/v1/Extensions.cs deleted file mode 100644 index 30a6c3b8b..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/Extensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using FSH.Framework.Tenant.Endpoints.v1.Activate; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; -public static class Extensions -{ - public static IEndpointRouteBuilder MapTenantEndpoints(this IEndpointRouteBuilder app) - { - var tenantGroup = app.MapGroup("api/tenants").WithTags("tenants"); - tenantGroup.MapRegisterTenantEndpoint(); - tenantGroup.MapGetTenantsEndpoint(); - tenantGroup.MapGetTenantByIdEndpoint(); - tenantGroup.MapUpgradeTenantSubscriptionEndpoint(); - tenantGroup.MapActivateTenantEndpoint(); - tenantGroup.MapDisableTenantEndpoint(); - return app; - } -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantById.cs b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantById.cs new file mode 100644 index 000000000..26742cdc9 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantById.cs @@ -0,0 +1,49 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Core.Abstractions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Infrastructure.Tenant.Endpoints; +public static class GetTenantById +{ + public sealed record Query(string TenantId) : IQuery; + public class Response + { + public string Id { get; set; } = default!; + public string Name { get; set; } = default!; + public string? ConnectionString { get; set; } + public string AdminEmail { get; set; } = default!; + public bool IsActive { get; set; } + public DateTime ValidUpto { get; set; } + public string? Issuer { get; set; } + } + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/{id}", (IQueryDispatcher dispatcher, string id) + => dispatcher.SendAsync(new Query(id))) + .WithName(nameof(GetTenantById)) + .WithSummary("get tenant by id") + .RequirePermission("Permissions.Tenants.View") + .WithDescription("get tenant by id"); + } + public sealed class Handler(ITenantService service) : IQueryHandler + { + public async Task HandleAsync(Query query, CancellationToken cancellationToken = default) + { + var tenant = await service.GetByIdAsync(query.TenantId); + return new Response() + { + Id = tenant.Id, + Name = tenant.Name, + ConnectionString = tenant.ConnectionString, + AdminEmail = tenant.AdminEmail, + IsActive = tenant.IsActive, + ValidUpto = tenant.ValidUpto, + Issuer = tenant.Issuer, + }; + } + } + +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs deleted file mode 100644 index ab4591269..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantByIdEndpoint.cs +++ /dev/null @@ -1,18 +0,0 @@ -using FSH.Framework.Core.Tenant.Features.GetTenantById; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; -public static class GetTenantByIdEndpoint -{ - internal static RouteHandlerBuilder MapGetTenantByIdEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/{id}", (ISender mediator, string id) - => mediator.Send(new GetTenantByIdQuery(id))) - .WithName(nameof(GetTenantByIdEndpoint)) - .WithSummary("get tenant by id") - .RequirePermission("Permissions.Tenants.View") - .WithDescription("get tenant by id"); - } -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenants.cs b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenants.cs new file mode 100644 index 000000000..17a977783 --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenants.cs @@ -0,0 +1,38 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Infrastructure.Tenant.Endpoints; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Core.Abstractions; +using Mapster; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Endpoints.v1; +public static class GetTenants +{ + public sealed class Query : IQuery; + public sealed class Response + { + public IReadOnlyCollection Tenants { get; init; } = []; + } + public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/", (IQueryDispatcher dispatcher) => dispatcher.SendAsync(new Query())) + .WithName(nameof(GetTenants)) + .WithSummary("get tenants") + .RequirePermission("Permissions.Tenants.View") + .WithDescription("get tenants"); + } + public sealed class GetTenantsHandler(ITenantService service) : IQueryHandler + { + public async Task HandleAsync(Query request, CancellationToken cancellationToken = default) + { + var tenants = await service.GetAllAsync(); + return new Response + { + Tenants = tenants.Adapt>() + }; + } + } + +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantsEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantsEndpoint.cs deleted file mode 100644 index 1bf590deb..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantsEndpoint.cs +++ /dev/null @@ -1,19 +0,0 @@ -using FSH.Framework.Core.Tenant.Features.GetTenants; -using FSH.Framework.Infrastructure.Auth.Policy; -using MediatR; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; -public static class GetTenantsEndpoint -{ - internal static RouteHandlerBuilder MapGetTenantsEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/", (ISender mediator) => mediator.Send(new GetTenantsQuery())) - .WithName(nameof(GetTenantsEndpoint)) - .WithSummary("get tenants") - .RequirePermission("Permissions.Tenants.View") - .WithDescription("get tenants"); - } -} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscription.cs b/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscription.cs new file mode 100644 index 000000000..f66d8f03d --- /dev/null +++ b/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscription.cs @@ -0,0 +1,42 @@ +using FluentValidation; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Core.Abstractions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Infrastructure.Tenant.Endpoints; + +public static class UpgradeSubscription +{ + public record Command(string Tenant, DateTime ExtendedExpiryDate) : ICommand; + public record Response(DateTime NewValidity, string Tenant); + public class Validator : AbstractValidator + { + public Validator() + { + RuleFor(t => t.Tenant).NotEmpty(); + RuleFor(t => t.ExtendedExpiryDate).GreaterThan(DateTime.UtcNow); + } + } + + + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/upgrade", (Command command, ICommandDispatcher dispatcher) => dispatcher.SendAsync(command)) + .WithName(nameof(UpgradeSubscription)) + .WithSummary("upgrade tenant subscription") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("upgrade tenant subscription"); + } + public class Handler(ITenantService service) : ICommandHandler + { + public async Task HandleAsync(Command request, CancellationToken cancellationToken = default) + { + var validUpto = await service.UpgradeSubscription(request.Tenant, request.ExtendedExpiryDate); + return new Response(validUpto, request.Tenant); + } + } + +} diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscriptionEndpoint.cs b/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscriptionEndpoint.cs deleted file mode 100644 index 182330544..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscriptionEndpoint.cs +++ /dev/null @@ -1,20 +0,0 @@ -using FSH.Framework.Core.Tenant.Features.UpgradeSubscription; -using FSH.Framework.Infrastructure.Auth.Policy; -using MediatR; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; - -public static class UpgradeSubscriptionEndpoint -{ - internal static RouteHandlerBuilder MapUpgradeTenantSubscriptionEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/upgrade", (UpgradeSubscriptionCommand command, ISender mediator) => mediator.Send(command)) - .WithName(nameof(UpgradeSubscriptionEndpoint)) - .WithSummary("upgrade tenant subscription") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("upgrade tenant subscription"); - } -} diff --git a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs index b34498367..844476707 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs @@ -2,8 +2,8 @@ using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Persistence; +using FSH.Framework.Core.Tenant; using FSH.Framework.Core.Tenant.Abstractions; -using FSH.Framework.Core.Tenant.Dtos; using FSH.Framework.Core.Tenant.Features.CreateTenant; using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Core.Abstractions; From df7f23e3b2a11d9ba7fe191849dcb978f369ff39 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 10 Apr 2025 18:47:34 +0530 Subject: [PATCH 22/54] cleanup --- src/framework/.editorconfig | 4 +++- .../Core/Caching/CacheServiceExtensions.cs | 8 ++++---- src/framework/Core/Caching/ICacheService.cs | 16 ++++++++-------- .../Users/UserService.Permissions.cs | 2 +- .../Caching/DistributedCacheService.cs | 16 ++++++++-------- .../Tenant/Tenant.Endpoints/v1/CreateTenant.cs | 1 - .../Tenant/Tenant.Infrastructure/Extensions.cs | 1 - .../Tenant.Infrastructure/TenantService.cs | 12 ++++++------ 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/framework/.editorconfig b/src/framework/.editorconfig index 121f35bc7..4f7e030d6 100644 --- a/src/framework/.editorconfig +++ b/src/framework/.editorconfig @@ -274,6 +274,7 @@ dotnet_diagnostic.IDE0053.severity = none # IDE0130: Namespace should match project structure dotnet_diagnostic.IDE0130.severity = none +dotnet_diagnostic.CA1032.severity = none [*.{cs,vb}] dotnet_style_operator_placement_when_wrapping = beginning_of_line @@ -290,4 +291,5 @@ 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_diagnostic.CA1711.severity = none \ No newline at end of file +dotnet_diagnostic.CA1711.severity = none +dotnet_diagnostic.CA1040.severity = none \ No newline at end of file diff --git a/src/framework/Core/Caching/CacheServiceExtensions.cs b/src/framework/Core/Caching/CacheServiceExtensions.cs index c03f94cc1..5f786e710 100644 --- a/src/framework/Core/Caching/CacheServiceExtensions.cs +++ b/src/framework/Core/Caching/CacheServiceExtensions.cs @@ -4,7 +4,7 @@ public static class CacheServiceExtensions { public static T? GetOrSet(this ICacheService cache, string key, Func getItemCallback, TimeSpan? slidingExpiration = null) { - T? value = cache.Get(key); + T? value = cache.GetItem(key); if (value is not null) { @@ -15,7 +15,7 @@ public static class CacheServiceExtensions if (value is not null) { - cache.Set(key, value, slidingExpiration); + cache.SetItem(key, value, slidingExpiration); } return value; @@ -23,7 +23,7 @@ public static class CacheServiceExtensions public static async Task GetOrSetAsync(this ICacheService cache, string key, Func> task, TimeSpan? slidingExpiration = null, CancellationToken cancellationToken = default) { - T? value = await cache.GetAsync(key, cancellationToken); + T? value = await cache.GetItemAsync(key, cancellationToken); if (value is not null) { @@ -34,7 +34,7 @@ public static class CacheServiceExtensions if (value is not null) { - await cache.SetAsync(key, value, slidingExpiration, cancellationToken); + await cache.SetItemAsync(key, value, slidingExpiration, cancellationToken); } return value; diff --git a/src/framework/Core/Caching/ICacheService.cs b/src/framework/Core/Caching/ICacheService.cs index 54f3c0904..c5538d71e 100644 --- a/src/framework/Core/Caching/ICacheService.cs +++ b/src/framework/Core/Caching/ICacheService.cs @@ -2,15 +2,15 @@ namespace FSH.Framework.Core.Caching; public interface ICacheService { - T? Get(string key); - Task GetAsync(string key, CancellationToken token = default); + T? GetItem(string key); + Task GetItemAsync(string key, CancellationToken token = default); - void Refresh(string key); - Task RefreshAsync(string key, CancellationToken token = default); + void RefreshItem(string key); + Task RefreshItemAsync(string key, CancellationToken token = default); - void Remove(string key); - Task RemoveAsync(string key, CancellationToken token = default); + void RemoveItem(string key); + Task RemoveItemAsync(string key, CancellationToken token = default); - void Set(string key, T value, TimeSpan? slidingExpiration = null); - Task SetAsync(string key, T value, TimeSpan? slidingExpiration = null, CancellationToken cancellationToken = default); + void SetItem(string key, T value, TimeSpan? slidingExpiration = null); + Task SetItemAsync(string key, T value, TimeSpan? slidingExpiration = null, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs b/src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs index d150028a6..2efd34cf6 100644 --- a/src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs +++ b/src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs @@ -46,6 +46,6 @@ public async Task HasPermissionAsync(string userId, string permission, Can public Task InvalidatePermissionCacheAsync(string userId, CancellationToken cancellationToken) { - return cache.RemoveAsync(GetPermissionCacheKey(userId), cancellationToken); + return cache.RemoveItemAsync(GetPermissionCacheKey(userId), cancellationToken); } } diff --git a/src/framework/Infrastructure/Caching/DistributedCacheService.cs b/src/framework/Infrastructure/Caching/DistributedCacheService.cs index f4353d69a..3b8aa6df2 100644 --- a/src/framework/Infrastructure/Caching/DistributedCacheService.cs +++ b/src/framework/Infrastructure/Caching/DistributedCacheService.cs @@ -16,7 +16,7 @@ public DistributedCacheService(IDistributedCache cache, ILogger(string key) => + public T? GetItem(string key) => Get(key) is { } data ? Deserialize(data) : default; @@ -35,7 +35,7 @@ public DistributedCacheService(IDistributedCache cache, ILogger GetAsync(string key, CancellationToken token = default) => + public async Task GetItemAsync(string key, CancellationToken token = default) => await GetAsync(key, token) is { } data ? Deserialize(data) : default; @@ -53,7 +53,7 @@ await GetAsync(key, token) is { } data } } - public void Refresh(string key) + public void RefreshItem(string key) { try { @@ -65,7 +65,7 @@ public void Refresh(string key) } } - public async Task RefreshAsync(string key, CancellationToken token = default) + public async Task RefreshItemAsync(string key, CancellationToken token = default) { try { @@ -78,7 +78,7 @@ public async Task RefreshAsync(string key, CancellationToken token = default) } } - public void Remove(string key) + public void RemoveItem(string key) { try { @@ -90,7 +90,7 @@ public void Remove(string key) } } - public async Task RemoveAsync(string key, CancellationToken token = default) + public async Task RemoveItemAsync(string key, CancellationToken token = default) { try { @@ -102,7 +102,7 @@ public async Task RemoveAsync(string key, CancellationToken token = default) } } - public void Set(string key, T value, TimeSpan? slidingExpiration = null) => + public void SetItem(string key, T value, TimeSpan? slidingExpiration = null) => Set(key, Serialize(value), slidingExpiration); private void Set(string key, byte[] value, TimeSpan? slidingExpiration = null) @@ -118,7 +118,7 @@ private void Set(string key, byte[] value, TimeSpan? slidingExpiration = null) } } - public Task SetAsync(string key, T value, TimeSpan? slidingExpiration = null, CancellationToken cancellationToken = default) => + public Task SetItemAsync(string key, T value, TimeSpan? slidingExpiration = null, CancellationToken cancellationToken = default) => SetAsync(key, Serialize(value), slidingExpiration, cancellationToken); private async Task SetAsync(string key, byte[] value, TimeSpan? slidingExpiration = null, CancellationToken token = default) diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs b/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs index 4843a3a9f..725b72830 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs +++ b/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs @@ -3,7 +3,6 @@ using FSH.Framework.Core.Persistence; using FSH.Framework.Shared.Authorization; using FSH.Framework.Tenant.Core.Abstractions; -using FSH.Framework.Tenant.Endpoints.v1.Activate; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs index 6963932c7..1e51a785a 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs @@ -2,7 +2,6 @@ using Finbuckle.MultiTenant.Abstractions; using Finbuckle.MultiTenant.Stores.DistributedCacheStore; using FSH.Framework.Core.Persistence; -using FSH.Framework.Core.Tenant.Abstractions; using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Infrastructure.Persistence.Services; using FSH.Framework.Shared.Constants; diff --git a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs index 844476707..5fa4e920f 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs +++ b/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs @@ -3,8 +3,6 @@ using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Persistence; using FSH.Framework.Core.Tenant; -using FSH.Framework.Core.Tenant.Abstractions; -using FSH.Framework.Core.Tenant.Features.CreateTenant; using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Core.Abstractions; using Mapster; @@ -42,15 +40,17 @@ public async Task ActivateAsync(string id, CancellationToken cancellatio return $"tenant {id} is now activated"; } - public async Task CreateAsync(CreateTenantCommand request, CancellationToken cancellationToken) + public async Task CreateAsync(string id, + string name, + string? connectionString, + string adminEmail, string? issuer, CancellationToken cancellationToken) { - var connectionString = request.ConnectionString; - if (request.ConnectionString?.Trim() == _config.ConnectionString.Trim()) + if (connectionString?.Trim() == _config.ConnectionString.Trim()) { connectionString = string.Empty; } - FshTenantInfo tenant = new(request.Id, request.Name, connectionString, request.AdminEmail, request.Issuer); + FshTenantInfo tenant = new(id, name, connectionString, adminEmail, issuer); await _tenantStore.TryAddAsync(tenant).ConfigureAwait(false); await InitializeDatabase(tenant).ConfigureAwait(false); From 95dd30bb0954db35b02a2e7a95e295df8321e61c Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Fri, 11 Apr 2025 00:41:54 +0530 Subject: [PATCH 23/54] clean auditing --- .../Auditing.Endpoints/AuditingModule.cs | 2 +- .../Auditing.Endpoints/v1/GetUserTrails.cs | 48 +++++++++++++++++++ .../GetUserTrails/GetUserTrails.Endpoint.cs | 28 ----------- .../v1/GetUserTrails/GetUserTrails.Handler.cs | 18 ------- .../v1/GetUserTrails/GetUserTrails.Query.cs | 7 --- .../GetUserTrails/GetUserTrails.Response.cs | 7 --- .../GetUserTrails/GetUserTrails.Validator.cs | 14 ------ 7 files changed, 49 insertions(+), 75 deletions(-) create mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Endpoint.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs index 71fb6a785..79ab48abf 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs @@ -1,5 +1,5 @@ using Asp.Versioning; -using FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; +using FSH.Framework.Auditing.Endpoints.v1; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Modules; using Microsoft.AspNetCore.Builder; diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs new file mode 100644 index 000000000..e4c859ed0 --- /dev/null +++ b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs @@ -0,0 +1,48 @@ +using FluentValidation; +using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Auditing.Endpoints.v1; +public static class GetUserTrails +{ + public sealed record Query(Guid UserId) : IQuery; + public sealed record Response(IReadOnlyList AuditTrails); + public sealed class Validator : AbstractValidator + { + public Validator() + { + RuleFor(x => x.UserId).NotEmpty(); + } + } + public sealed class Handler(IAuditService auditService) + : IQueryHandler + { + public async Task HandleAsync(Query query, CancellationToken cancellationToken = default) + { + var trails = await auditService.GetUserTrailsAsync(query.UserId); + return new Response(trails); + } + } + public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/users/{userId:guid}/trails", async ( + Guid userId, + IQueryDispatcher dispatcher, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync( + new Query(userId), cancellationToken); + + return TypedResults.Ok(result); + }) + .WithName("GetUserTrails") + .WithSummary("Get user's audit trail details") + .WithDescription("Returns the audit trail details for a specific user.") + .RequirePermission("Permissions.AuditTrails.View"); + } +} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Endpoint.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Endpoint.cs deleted file mode 100644 index 870591691..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Endpoint.cs +++ /dev/null @@ -1,28 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -public static partial class GetUserTrails -{ - public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/users/{userId:guid}/trails", async ( - Guid userId, - IQueryDispatcher dispatcher, - CancellationToken cancellationToken) => - { - var result = await dispatcher.SendAsync( - new Query(userId), cancellationToken); - - return TypedResults.Ok(result); - }) - .WithName("GetUserTrails") - .WithSummary("Get user's audit trail details") - .WithDescription("Returns the audit trail details for a specific user.") - .RequirePermission("Permissions.AuditTrails.View"); - } -} - diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs deleted file mode 100644 index 54ae7a2c4..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Handler.cs +++ /dev/null @@ -1,18 +0,0 @@ -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Core.Messaging.CQRS; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; - -public static partial class GetUserTrails -{ - public sealed class Handler(IAuditService auditService) - : IQueryHandler - { - public async Task HandleAsync(Query query, CancellationToken cancellationToken = default) - { - var trails = await auditService.GetUserTrailsAsync(query.UserId); - return new Response(trails); - } - } -} - diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs deleted file mode 100644 index 251bd53e8..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Query.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -public static partial class GetUserTrails -{ - public sealed record Query(Guid UserId) : IQuery; -} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs deleted file mode 100644 index e3f83ff6b..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Response.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FSH.Framework.Auditing.Contracts; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; -public static partial class GetUserTrails -{ - public sealed record Response(IReadOnlyList AuditTrails); -} diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs deleted file mode 100644 index 3975190a1..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails/GetUserTrails.Validator.cs +++ /dev/null @@ -1,14 +0,0 @@ -using FluentValidation; - -namespace FSH.Framework.Auditing.Endpoints.v1.GetUserTrails; - -public static partial class GetUserTrails -{ - public sealed class Validator : AbstractValidator - { - public Validator() - { - RuleFor(x => x.UserId).NotEmpty(); - } - } -} From 79f51af4b5be4e4d2cfb74da4c82ba139c9ee501 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Sat, 12 Apr 2025 11:51:35 +0530 Subject: [PATCH 24/54] structure change (again!) --- src/framework/.editorconfig | 1 + src/framework/Application/Application.csproj | 16 --- .../Behaviors/ValidationBehavior.cs | 40 ------ .../Events/AuditPublishedEvent.cs | 13 -- .../Auditing/Auditing.Contracts/Trail.cs | 96 -------------- .../Abstractions/IAuditService.cs | 7 - .../Auditing.Core/Auditing.Core.csproj | 13 -- .../Auditing.Endpoints.csproj | 14 -- .../Auditing.Endpoints/v1/GetUserTrails.cs | 48 ------- .../Auditing.Infrastructure.csproj | 13 -- .../AuditingConstants.cs | 5 - src/framework/Core/Helpers/JsonHelpers.cs | 13 ++ .../Core/Messaging/CQRS/ICommandDispatcher.cs | 3 +- .../Core/Messaging/CQRS/IQueryDispatcher.cs | 6 +- .../Core/Messaging/Events/IEventHandler.cs | 2 +- .../Core/Messaging/Events/IEventPublisher.cs | 2 +- src/framework/Directory.Build.props | 4 +- src/framework/FSH.Framework.sln | 125 +++++++----------- .../AssignUserRole/AssignUserRoleCommand.cs | 11 -- .../Extensions/PagedListExtensions.cs | 0 .../Extensions/RepositoryExtensions.cs | 0 .../Endpoints/AssignRolesToUserEndpoint.cs | 28 ---- .../Messaging/CQRS/CommandDispatcher.cs | 10 +- .../Messaging/CQRS/QueryDispatcher.cs | 9 +- .../CQRS/Validation/CommandValidation.cs | 9 +- .../CQRS/Validation/QueryValidation.cs | 9 +- .../CQRS/Validation/ValidationHelper.cs | 33 +++-- .../Infrastructure/Modules/IEndpoint.cs | 8 ++ .../{IEndpointModule.cs => IModule.cs} | 2 +- .../Auditing.Contracts.csproj | 3 + .../Auditing.Contracts/AuditingConstants.cs | 18 +++ .../Auditing.Contracts/Dtos/TrailDto.cs | 16 +++ .../Enums/AuditOperation.cs | 0 .../IntegrationEvents/AuditPublishedEvent.cs | 14 ++ .../v1/GetUserTrails/GetUserTrailsQuery.cs | 4 + .../GetUserTrailsQueryResponse.cs | 4 + .../Modules/Auditing/Auditing.csproj | 18 +++ .../Auditing}/AuditingModule.cs | 9 +- .../Auditing}/Data/AuditingConfiguration.cs | 3 +- .../Auditing}/Data/AuditingDbContext.cs | 6 +- .../Auditing/Data}/IAuditingDbContext.cs | 4 +- .../Data}/Interceptors/AuditInterceptor.cs | 6 +- .../AuditPublishedIntegrationEventHandler.cs} | 15 ++- .../Auditing/Features/Entities/Trail.cs | 69 ++++++++++ .../GetUserTrailsQueryEndpoint.cs | 27 ++++ .../GetUserTrailsQueryHandler.cs | 14 ++ .../GetUserTrailsQueryValidator.cs | 11 ++ .../Modules/Auditing/GlobalSuppressions.cs | 8 ++ .../Auditing/Mappings/TrailMappings.cs | 54 ++++++++ .../Auditing}/Services/AuditService.cs | 12 +- .../Auditing/Services/IAuditService.cs | 7 + .../Identity.Core/Identity.Core.csproj | 3 + .../Roles/CreateOrUpdateRoleRequest.cs | 4 + .../Identity.Core/Roles/IRoleService.cs | 4 +- .../Identity/Identity.Core/Roles/RoleDto.cs | 2 +- .../Roles/UpdatePermissionsRequest.cs | 4 + .../Identity.Core/Roles/UserRoleDetailDto.cs} | 4 +- .../Identity.Core/Tokens/ITokenService.cs | 0 .../Identity/Identity.Core/Tokens/TokenDto.cs | 0 .../Tokens/TokenGenerationRequest.cs | 2 +- .../Tokens/TokenRefreshRequest.cs | 0 .../Users/ICurrentUserInitializer.cs | 0 .../Identity.Core/Users/IUserService.cs | 13 +- .../Identity.Core/Users/UserDetailDto.cs} | 4 +- .../Identity.Endpoints.csproj | 4 +- .../CreateOrUpdateRoleCommand.cs | 0 .../CreateOrUpdateRoleValidator.cs | 0 .../UpdatePermissionsCommand.cs | 0 .../UpdatePermissionsValidator.cs | 0 .../v1/Tokens/RefreshToken.cs | 2 +- .../v1/Tokens/TokenGeneration.cs | 2 +- .../v1/Users/AssignUserRoles.cs | 36 +++++ .../ChangePassword/ChangePasswordCommand.cs | 0 .../ChangePassword/ChangePasswordValidator.cs | 0 .../ForgotPassword/ForgotPasswordCommand.cs | 0 .../ForgotPassword/ForgotPasswordValidator.cs | 0 .../Users/RegisterUser/RegisterUserCommand.cs | 0 .../RegisterUser/RegisterUserResponse.cs | 0 .../ResetPassword/ResetPasswordCommand.cs | 0 .../ResetPassword/ResetPasswordValidator.cs | 0 .../ToggleUserStatusCommand.cs | 0 .../v1/Users/UpdateUser/UpdateUserCommand.cs | 0 .../UpdateUser/UpdateUserCommandValidator.cs | 0 .../PermissionAuthorizationRequirement.cs | 0 ...quiredPermissionAuthorizationExtensions.cs | 0 .../RequiredPermissionAuthorizationHandler.cs | 0 .../Data/IdentityConfigurations.cs | 0 .../Data/IdentityDbContext.cs | 0 .../Data/IdentityDbInitializer.cs | 0 .../Identity.Infrastructure.csproj | 6 +- .../IdentityConstants.cs | 0 .../Identity.Infrastructure/JwtOptions.cs | 0 .../Identity.Infrastructure/Roles/FshRole.cs | 0 .../Tokens/TokenService.cs | 0 .../Users/CurrentUserService.cs | 0 .../Identity.Infrastructure/Users/FshUser.cs | 0 .../Users/UserService.Password.cs | 0 .../Users/UserService.Permissions.cs | 0 .../Users/UserService.cs | 18 +-- .../Tenant.Contracts/Tenant.Contracts.csproj | 12 ++ .../Tenant.Contracts/TenantConstants.cs | 4 + .../Tenant}/Data/TenantDbContext.cs | 2 +- .../Tenant}/Extensions.cs | 6 +- .../Tenant/Features}/v1/ActivateTenant.cs | 6 +- .../Tenant/Features}/v1/CreateTenant.cs | 6 +- .../Tenant/Features}/v1/DisableTenant.cs | 6 +- .../Tenant/Features}/v1/GetTenantById.cs | 10 +- .../Tenant/Features}/v1/GetTenants.cs | 7 +- .../Features}/v1/UpgradeSubscription.cs | 17 ++- .../Tenant/Services}/ITenantService.cs | 4 +- .../Tenant/Services}/TenantService.cs | 4 +- src/framework/Modules/Tenant/Tenant.csproj | 16 +++ .../Tenant}/TenantDetail.cs | 2 +- .../Tenant}/TenantModule.cs | 7 +- .../Tenant/Tenant.Core/Tenant.Core.csproj | 10 -- .../Tenant.Endpoints/Tenant.Endpoints.csproj | 18 --- .../Tenant.Infrastructure.csproj | 17 --- 117 files changed, 561 insertions(+), 563 deletions(-) delete mode 100644 src/framework/Application/Application.csproj delete mode 100644 src/framework/Application/Behaviors/ValidationBehavior.cs delete mode 100644 src/framework/Auditing/Auditing.Contracts/Events/AuditPublishedEvent.cs delete mode 100644 src/framework/Auditing/Auditing.Contracts/Trail.cs delete mode 100644 src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs delete mode 100644 src/framework/Auditing/Auditing.Core/Auditing.Core.csproj delete mode 100644 src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj delete mode 100644 src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs delete mode 100644 src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj delete mode 100644 src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs create mode 100644 src/framework/Core/Helpers/JsonHelpers.cs delete mode 100644 src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs rename src/framework/{Application => Infrastructure}/Extensions/PagedListExtensions.cs (100%) rename src/framework/{Application => Infrastructure}/Extensions/RepositoryExtensions.cs (100%) delete mode 100644 src/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs create mode 100644 src/framework/Infrastructure/Modules/IEndpoint.cs rename src/framework/Infrastructure/Modules/{IEndpointModule.cs => IModule.cs} (80%) rename src/framework/{Auditing => Modules}/Auditing.Contracts/Auditing.Contracts.csproj (80%) create mode 100644 src/framework/Modules/Auditing.Contracts/AuditingConstants.cs create mode 100644 src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs rename src/framework/{Auditing => Modules}/Auditing.Contracts/Enums/AuditOperation.cs (100%) create mode 100644 src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs create mode 100644 src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs create mode 100644 src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs create mode 100644 src/framework/Modules/Auditing/Auditing.csproj rename src/framework/{Auditing/Auditing.Endpoints => Modules/Auditing}/AuditingModule.cs (80%) rename src/framework/{Auditing/Auditing.Infrastructure => Modules/Auditing}/Data/AuditingConfiguration.cs (84%) rename src/framework/{Auditing/Auditing.Infrastructure => Modules/Auditing}/Data/AuditingDbContext.cs (74%) rename src/framework/{Auditing/Auditing.Core/Abstractions => Modules/Auditing/Data}/IAuditingDbContext.cs (65%) rename src/framework/{Auditing/Auditing.Infrastructure => Modules/Auditing/Data}/Interceptors/AuditInterceptor.cs (97%) rename src/framework/{Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs => Modules/Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs} (70%) create mode 100644 src/framework/Modules/Auditing/Features/Entities/Trail.cs create mode 100644 src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryEndpoint.cs create mode 100644 src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs create mode 100644 src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs create mode 100644 src/framework/Modules/Auditing/GlobalSuppressions.cs create mode 100644 src/framework/Modules/Auditing/Mappings/TrailMappings.cs rename src/framework/{Auditing/Auditing.Infrastructure => Modules/Auditing}/Services/AuditService.cs (51%) create mode 100644 src/framework/Modules/Auditing/Services/IAuditService.cs rename src/framework/{ => Modules}/Identity/Identity.Core/Identity.Core.csproj (69%) create mode 100644 src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs rename src/framework/{ => Modules}/Identity/Identity.Core/Roles/IRoleService.cs (68%) rename src/framework/{ => Modules}/Identity/Identity.Core/Roles/RoleDto.cs (76%) create mode 100644 src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs rename src/framework/{Identity/Identity.Core/Dtos/UserRoleDetail.cs => Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs} (67%) rename src/framework/{ => Modules}/Identity/Identity.Core/Tokens/ITokenService.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Core/Tokens/TokenDto.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs (83%) rename src/framework/{ => Modules}/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Core/Users/ICurrentUserInitializer.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Core/Users/IUserService.cs (74%) rename src/framework/{Identity/Identity.Core/Dtos/UserDetail.cs => Modules/Identity/Identity.Core/Users/UserDetailDto.cs} (83%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/Identity.Endpoints.csproj (80%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs (95%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs (95%) create mode 100644 src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj (75%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/IdentityConstants.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/JwtOptions.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Roles/FshRole.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Tokens/TokenService.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Users/CurrentUserService.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Users/FshUser.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Users/UserService.Password.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.Infrastructure/Users/UserService.cs (95%) create mode 100644 src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj create mode 100644 src/framework/Modules/Tenant.Contracts/TenantConstants.cs rename src/framework/{Tenant/Tenant.Infrastructure => Modules/Tenant}/Data/TenantDbContext.cs (93%) rename src/framework/{Tenant/Tenant.Infrastructure => Modules/Tenant}/Extensions.cs (97%) rename src/framework/{Tenant/Tenant.Endpoints => Modules/Tenant/Features}/v1/ActivateTenant.cs (89%) rename src/framework/{Tenant/Tenant.Endpoints => Modules/Tenant/Features}/v1/CreateTenant.cs (94%) rename src/framework/{Tenant/Tenant.Endpoints => Modules/Tenant/Features}/v1/DisableTenant.cs (89%) rename src/framework/{Tenant/Tenant.Endpoints => Modules/Tenant/Features}/v1/GetTenantById.cs (83%) rename src/framework/{Tenant/Tenant.Endpoints => Modules/Tenant/Features}/v1/GetTenants.cs (86%) rename src/framework/{Tenant/Tenant.Endpoints => Modules/Tenant/Features}/v1/UpgradeSubscription.cs (71%) rename src/framework/{Tenant/Tenant.Core/Abstractions => Modules/Tenant/Services}/ITenantService.cs (87%) rename src/framework/{Tenant/Tenant.Infrastructure => Modules/Tenant/Services}/TenantService.cs (97%) create mode 100644 src/framework/Modules/Tenant/Tenant.csproj rename src/framework/{Tenant/Tenant.Core => Modules/Tenant}/TenantDetail.cs (89%) rename src/framework/{Tenant/Tenant.Endpoints => Modules/Tenant}/TenantModule.cs (88%) delete mode 100644 src/framework/Tenant/Tenant.Core/Tenant.Core.csproj delete mode 100644 src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj delete mode 100644 src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj diff --git a/src/framework/.editorconfig b/src/framework/.editorconfig index 4f7e030d6..44ec867d8 100644 --- a/src/framework/.editorconfig +++ b/src/framework/.editorconfig @@ -275,6 +275,7 @@ dotnet_diagnostic.IDE0053.severity = none # IDE0130: Namespace should match project structure dotnet_diagnostic.IDE0130.severity = none dotnet_diagnostic.CA1032.severity = none +dotnet_diagnostic.S2326.severity = none [*.{cs,vb}] dotnet_style_operator_placement_when_wrapping = beginning_of_line diff --git a/src/framework/Application/Application.csproj b/src/framework/Application/Application.csproj deleted file mode 100644 index bf8a4ab17..000000000 --- a/src/framework/Application/Application.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - FSH.Framework.Application - FSH.Framework.Application - - - - - - - - - - - - diff --git a/src/framework/Application/Behaviors/ValidationBehavior.cs b/src/framework/Application/Behaviors/ValidationBehavior.cs deleted file mode 100644 index 80cc3a68e..000000000 --- a/src/framework/Application/Behaviors/ValidationBehavior.cs +++ /dev/null @@ -1,40 +0,0 @@ -using FluentValidation; -using MediatR; - -namespace FSH.Framework.Application.Behaviors; - -public class ValidationBehavior : IPipelineBehavior - where TRequest : IRequest -{ - private readonly IEnumerable> _validators; - - public ValidationBehavior(IEnumerable> validators) - { - _validators = validators; - } - - public async Task Handle( - TRequest request, - RequestHandlerDelegate next, - CancellationToken cancellationToken) - { - if (_validators.Any()) - { - var context = new ValidationContext(request); - - var validationResults = await Task.WhenAll( - _validators.Select(v => v.ValidateAsync(context, cancellationToken)) - ); - - var failures = validationResults - .SelectMany(result => result.Errors) - .Where(error => error is not null) - .ToList(); - - if (failures.Count > 0) - throw new ValidationException(failures); - } - - return await next(cancellationToken); - } -} diff --git a/src/framework/Auditing/Auditing.Contracts/Events/AuditPublishedEvent.cs b/src/framework/Auditing/Auditing.Contracts/Events/AuditPublishedEvent.cs deleted file mode 100644 index c6fdea919..000000000 --- a/src/framework/Auditing/Auditing.Contracts/Events/AuditPublishedEvent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using FSH.Framework.Core.Messaging.Events; - -namespace FSH.Framework.Auditing.Contracts.Events; - -public class AuditPublishedEvent : INotification -{ - public IReadOnlyCollection Trails { get; } - - public AuditPublishedEvent(IReadOnlyCollection trails) - { - Trails = trails; - } -} diff --git a/src/framework/Auditing/Auditing.Contracts/Trail.cs b/src/framework/Auditing/Auditing.Contracts/Trail.cs deleted file mode 100644 index 9b75c7f7b..000000000 --- a/src/framework/Auditing/Auditing.Contracts/Trail.cs +++ /dev/null @@ -1,96 +0,0 @@ -using FSH.Framework.Auditing.Contracts.Enums; -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text.Json; - -namespace FSH.Framework.Auditing.Contracts; - -public class Trail -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public DateTimeOffset DateTime { get; set; } - public AuditOperation Operation { get; set; } // e.g., "Create", "Update", "Delete" - public required string Description { get; set; } - public string? EntityName { get; set; } // Name of the entity/table affected - - // Store dictionaries as JSON in the database - [Column(TypeName = "jsonb")] - public string KeyValuesJson { get; set; } = string.Empty; - - [Column(TypeName = "jsonb")] - public string OldValuesJson { get; set; } = string.Empty; - - [Column(TypeName = "jsonb")] - public string NewValuesJson { get; set; } = string.Empty; - - // Store ModifiedProperties as JSON - [Column(TypeName = "jsonb")] - public string ModifiedPropertiesJson { get; set; } = string.Empty; - - // Convert JSON back to Dictionary or List when needed - public Dictionary KeyValues - { - get => JsonSerializer.Deserialize>(KeyValuesJson) ?? new Dictionary(); - set => KeyValuesJson = JsonSerializer.Serialize(value); - } - - [NotMapped] - public IReadOnlyDictionary OldValues => - JsonSerializer.Deserialize>(OldValuesJson) - ?? new Dictionary(); - - public void SetOldValues(Dictionary values) => - OldValuesJson = JsonSerializer.Serialize(values); - public void SetOldValue(string key, object? value) - { - var dict = JsonSerializer.Deserialize>(OldValuesJson) - ?? new Dictionary(); - - dict[key] = value; - - OldValuesJson = JsonSerializer.Serialize(dict); - } - - // --- NewValues --- - - [NotMapped] - public IReadOnlyDictionary NewValues => - JsonSerializer.Deserialize>(NewValuesJson) - ?? new Dictionary(); - - public void SetNewValues(Dictionary values) => - NewValuesJson = JsonSerializer.Serialize(values); - - public void SetNewValue(string key, object? value) - { - var dict = JsonSerializer.Deserialize>(NewValuesJson) - ?? new Dictionary(); - - dict[key] = value; - - NewValuesJson = JsonSerializer.Serialize(dict); - } - - // --- ModifiedProperties --- - - [NotMapped] - public IReadOnlyCollection ModifiedProperties => - JsonSerializer.Deserialize>(ModifiedPropertiesJson) - ?? new Collection(); - - public void SetModifiedProperties(Collection values) => - ModifiedPropertiesJson = JsonSerializer.Serialize(values); - - public void AddModifiedProperty(string propertyName) - { - var list = JsonSerializer.Deserialize>(ModifiedPropertiesJson) - ?? new Collection(); - - if (!list.Contains(propertyName)) - list.Add(propertyName); - - ModifiedPropertiesJson = JsonSerializer.Serialize(list); - } - -} diff --git a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs b/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs deleted file mode 100644 index 2ab2cdf9b..000000000 --- a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditService.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FSH.Framework.Auditing.Contracts; - -namespace FSH.Framework.Auditing.Core.Abstractions; -public interface IAuditService -{ - Task> GetUserTrailsAsync(Guid userId); -} diff --git a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj b/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj deleted file mode 100644 index de35dbc71..000000000 --- a/src/framework/Auditing/Auditing.Core/Auditing.Core.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - FSH.Framework.Auditing.Core - FSH.Framework.Auditing.Core - - - - - - - - - diff --git a/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj b/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj deleted file mode 100644 index bcdbf7784..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/Auditing.Endpoints.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - FSH.Framework.Auditing.Endpoints - FSH.Framework.Auditing.Endpoints - - - - - - - - - - diff --git a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs b/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs deleted file mode 100644 index e4c859ed0..000000000 --- a/src/framework/Auditing/Auditing.Endpoints/v1/GetUserTrails.cs +++ /dev/null @@ -1,48 +0,0 @@ -using FluentValidation; -using FSH.Framework.Auditing.Contracts; -using FSH.Framework.Auditing.Core.Abstractions; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Auditing.Endpoints.v1; -public static class GetUserTrails -{ - public sealed record Query(Guid UserId) : IQuery; - public sealed record Response(IReadOnlyList AuditTrails); - public sealed class Validator : AbstractValidator - { - public Validator() - { - RuleFor(x => x.UserId).NotEmpty(); - } - } - public sealed class Handler(IAuditService auditService) - : IQueryHandler - { - public async Task HandleAsync(Query query, CancellationToken cancellationToken = default) - { - var trails = await auditService.GetUserTrailsAsync(query.UserId); - return new Response(trails); - } - } - public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/users/{userId:guid}/trails", async ( - Guid userId, - IQueryDispatcher dispatcher, - CancellationToken cancellationToken) => - { - var result = await dispatcher.SendAsync( - new Query(userId), cancellationToken); - - return TypedResults.Ok(result); - }) - .WithName("GetUserTrails") - .WithSummary("Get user's audit trail details") - .WithDescription("Returns the audit trail details for a specific user.") - .RequirePermission("Permissions.AuditTrails.View"); - } -} diff --git a/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj b/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj deleted file mode 100644 index b25bae7b5..000000000 --- a/src/framework/Auditing/Auditing.Infrastructure/Auditing.Infrastructure.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - FSH.Framework.Auditing.Infrastructure - FSH.Framework.Auditing.Infrastructure - - - - - - - - - diff --git a/src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs b/src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs deleted file mode 100644 index be53107d2..000000000 --- a/src/framework/Auditing/Auditing.Infrastructure/AuditingConstants.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace FSH.Framework.Auditing.Infrastructure; -public static class AuditingConstants -{ - public const string SchemaName = "auditing"; -} diff --git a/src/framework/Core/Helpers/JsonHelpers.cs b/src/framework/Core/Helpers/JsonHelpers.cs new file mode 100644 index 000000000..0ef4c7c47 --- /dev/null +++ b/src/framework/Core/Helpers/JsonHelpers.cs @@ -0,0 +1,13 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace FSH.Framework.Core.Helpers; +public static class JsonHelpers +{ + public static readonly JsonSerializerOptions DefaultJsonOptions = new(JsonSerializerDefaults.Web) + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = false, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; +} diff --git a/src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs b/src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs index aea040f7b..ebc5e4200 100644 --- a/src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs +++ b/src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs @@ -4,6 +4,5 @@ public interface ICommandDispatcher /// /// Sends a command to its handler. /// - Task SendAsync(TCommand command, CancellationToken ct = default) - where TCommand : ICommand; + Task SendAsync(ICommand command, CancellationToken ct = default); } diff --git a/src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs b/src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs index 2eb5d5ae3..ed0096d2f 100644 --- a/src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs +++ b/src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs @@ -1,9 +1,5 @@ namespace FSH.Framework.Core.Messaging.CQRS; public interface IQueryDispatcher { - /// - /// Sends a query to its handler. - /// - Task SendAsync(TQuery query, CancellationToken ct = default) - where TQuery : IQuery; + Task SendAsync(IQuery query, CancellationToken ct = default); } diff --git a/src/framework/Core/Messaging/Events/IEventHandler.cs b/src/framework/Core/Messaging/Events/IEventHandler.cs index 43e37ba3c..88e581319 100644 --- a/src/framework/Core/Messaging/Events/IEventHandler.cs +++ b/src/framework/Core/Messaging/Events/IEventHandler.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Core.Messaging.Events; public interface IEventHandler { - Task HandleAsync(TEvent @event, CancellationToken cancellationToken = default); + Task HandleAsync(TEvent appEvent, CancellationToken cancellationToken = default); } diff --git a/src/framework/Core/Messaging/Events/IEventPublisher.cs b/src/framework/Core/Messaging/Events/IEventPublisher.cs index d56b696ac..004828325 100644 --- a/src/framework/Core/Messaging/Events/IEventPublisher.cs +++ b/src/framework/Core/Messaging/Events/IEventPublisher.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Core.Messaging.Events; public interface IEventPublisher { - Task PublishAsync(TEvent @event, CancellationToken cancellationToken = default); + Task PublishAsync(TEvent appEvent, CancellationToken cancellationToken = default); } diff --git a/src/framework/Directory.Build.props b/src/framework/Directory.Build.props index d6449ac52..30bad8c2b 100644 --- a/src/framework/Directory.Build.props +++ b/src/framework/Directory.Build.props @@ -9,8 +9,8 @@ enable - true - true + false + false true latest AllEnabledByDefault diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index a4d9e3a8b..018804e29 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -7,38 +7,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{60DF219E-E1EB-428E-BB1F-F0342D42699F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application", "Application\Application.csproj", "{63773336-64B9-4A55-B1EA-EEF18BDF73D9}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{15EA2212-0958-4415-AA37-116F2A47F23F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tenant", "Tenant", "{24E922E3-8C91-43A1-A110-D8F5276566BA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Core", "Identity\Identity.Core\Identity.Core.csproj", "{D59824CA-B55C-4D45-B485-771B31FE7575}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Infrastructure", "Identity\Identity.Infrastructure\Identity.Infrastructure.csproj", "{8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Endpoints", "Identity\Identity.Endpoints\Identity.Endpoints.csproj", "{CE91E947-D5FA-499A-BB28-373CB8209813}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auditing", "Auditing", "{E5141F38-2D08-44DA-9A6C-B96890515168}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Core", "Auditing\Auditing.Core\Auditing.Core.csproj", "{0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Infrastructure", "Auditing\Auditing.Infrastructure\Auditing.Infrastructure.csproj", "{C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Endpoints", "Auditing\Auditing.Endpoints\Auditing.Endpoints.csproj", "{C8DCA061-E4D6-414F-9053-0723B6764D71}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{09380C15-F138-4305-A595-F4C7E16B6E78}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Core", "Tenant\Tenant.Core\Tenant.Core.csproj", "{AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Endpoints", "Tenant\Tenant.Endpoints\Tenant.Endpoints.csproj", "{86BC889E-322A-460E-81B6-601EE65B37C1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Infrastructure", "Tenant\Tenant.Infrastructure\Tenant.Infrastructure.csproj", "{F8AE32F3-31B9-4962-BE7A-1326BD13B739}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Contracts", "Auditing\Auditing.Contracts\Auditing.Contracts.csproj", "{7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -46,6 +24,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Packages.props = Directory.Packages.props EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Core", "Modules\Identity\Identity.Core\Identity.Core.csproj", "{DC442C2B-54EF-9A66-D650-6074EFA7E311}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Endpoints", "Modules\Identity\Identity.Endpoints\Identity.Endpoints.csproj", "{097D652F-5C24-57C7-B542-2C46739B3B30}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Infrastructure", "Modules\Identity\Identity.Infrastructure\Identity.Infrastructure.csproj", "{32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing", "Modules\Auditing\Auditing.csproj", "{BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Contracts", "Modules\Auditing.Contracts\Auditing.Contracts.csproj", "{E39A5A4F-D453-A6A2-CA94-468FD795246C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant", "Modules\Tenant\Tenant.csproj", "{27806993-447E-9781-647B-06D3F4AC834A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Contracts", "Modules\Tenant.Contracts\Tenant.Contracts.csproj", "{5324A0FF-DBB9-440C-80C2-4891EC719155}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -60,54 +52,38 @@ Global {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Debug|Any CPU.Build.0 = Debug|Any CPU {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Release|Any CPU.ActiveCfg = Release|Any CPU {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Release|Any CPU.Build.0 = Release|Any CPU - {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {63773336-64B9-4A55-B1EA-EEF18BDF73D9}.Release|Any CPU.Build.0 = Release|Any CPU - {D59824CA-B55C-4D45-B485-771B31FE7575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D59824CA-B55C-4D45-B485-771B31FE7575}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D59824CA-B55C-4D45-B485-771B31FE7575}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D59824CA-B55C-4D45-B485-771B31FE7575}.Release|Any CPU.Build.0 = Release|Any CPU - {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC}.Release|Any CPU.Build.0 = Release|Any CPU - {CE91E947-D5FA-499A-BB28-373CB8209813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE91E947-D5FA-499A-BB28-373CB8209813}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE91E947-D5FA-499A-BB28-373CB8209813}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE91E947-D5FA-499A-BB28-373CB8209813}.Release|Any CPU.Build.0 = Release|Any CPU - {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2}.Release|Any CPU.Build.0 = Release|Any CPU - {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786}.Release|Any CPU.Build.0 = Release|Any CPU - {C8DCA061-E4D6-414F-9053-0723B6764D71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C8DCA061-E4D6-414F-9053-0723B6764D71}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C8DCA061-E4D6-414F-9053-0723B6764D71}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C8DCA061-E4D6-414F-9053-0723B6764D71}.Release|Any CPU.Build.0 = Release|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Debug|Any CPU.Build.0 = Debug|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.ActiveCfg = Release|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.Build.0 = Release|Any CPU - {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6}.Release|Any CPU.Build.0 = Release|Any CPU - {86BC889E-322A-460E-81B6-601EE65B37C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86BC889E-322A-460E-81B6-601EE65B37C1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86BC889E-322A-460E-81B6-601EE65B37C1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86BC889E-322A-460E-81B6-601EE65B37C1}.Release|Any CPU.Build.0 = Release|Any CPU - {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F8AE32F3-31B9-4962-BE7A-1326BD13B739}.Release|Any CPU.Build.0 = Release|Any CPU - {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55}.Release|Any CPU.Build.0 = Release|Any CPU + {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Release|Any CPU.Build.0 = Release|Any CPU + {097D652F-5C24-57C7-B542-2C46739B3B30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {097D652F-5C24-57C7-B542-2C46739B3B30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {097D652F-5C24-57C7-B542-2C46739B3B30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {097D652F-5C24-57C7-B542-2C46739B3B30}.Release|Any CPU.Build.0 = Release|Any CPU + {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Release|Any CPU.Build.0 = Release|Any CPU + {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Release|Any CPU.Build.0 = Release|Any CPU + {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Release|Any CPU.Build.0 = Release|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.Build.0 = Release|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -115,17 +91,14 @@ Global GlobalSection(NestedProjects) = preSolution {15EA2212-0958-4415-AA37-116F2A47F23F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {24E922E3-8C91-43A1-A110-D8F5276566BA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {D59824CA-B55C-4D45-B485-771B31FE7575} = {15EA2212-0958-4415-AA37-116F2A47F23F} - {8A878DED-CC16-4D59-BFFD-C05F7EC26BDC} = {15EA2212-0958-4415-AA37-116F2A47F23F} - {CE91E947-D5FA-499A-BB28-373CB8209813} = {15EA2212-0958-4415-AA37-116F2A47F23F} {E5141F38-2D08-44DA-9A6C-B96890515168} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {0B7E4D65-D608-48D4-BBB4-340A6DAE88B2} = {E5141F38-2D08-44DA-9A6C-B96890515168} - {C3B569BA-0E98-41FB-8BC8-AC88A5ADE786} = {E5141F38-2D08-44DA-9A6C-B96890515168} - {C8DCA061-E4D6-414F-9053-0723B6764D71} = {E5141F38-2D08-44DA-9A6C-B96890515168} - {AD14C8C7-7A0A-40E1-88C9-3F535B89C7E6} = {24E922E3-8C91-43A1-A110-D8F5276566BA} - {86BC889E-322A-460E-81B6-601EE65B37C1} = {24E922E3-8C91-43A1-A110-D8F5276566BA} - {F8AE32F3-31B9-4962-BE7A-1326BD13B739} = {24E922E3-8C91-43A1-A110-D8F5276566BA} - {7A14CE7C-8D6A-4AF2-9F28-5E981C77DE55} = {E5141F38-2D08-44DA-9A6C-B96890515168} + {DC442C2B-54EF-9A66-D650-6074EFA7E311} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {097D652F-5C24-57C7-B542-2C46739B3B30} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B} = {E5141F38-2D08-44DA-9A6C-B96890515168} + {E39A5A4F-D453-A6A2-CA94-468FD795246C} = {E5141F38-2D08-44DA-9A6C-B96890515168} + {27806993-447E-9781-647B-06D3F4AC834A} = {24E922E3-8C91-43A1-A110-D8F5276566BA} + {5324A0FF-DBB9-440C-80C2-4891EC719155} = {24E922E3-8C91-43A1-A110-D8F5276566BA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs b/src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs deleted file mode 100644 index 491777145..000000000 --- a/src/framework/Identity/Identity.Endpoints/v1/Users/AssignUserRole/AssignUserRoleCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using FSH.Framework.Core.Identity.Users.Dtos; - -namespace FSH.Framework.Identity.Endpoints.v1.Users.AssignUserRole; - -public class AssignUserRoleCommand -{ - /// - /// A list of user-role assignment entries. - /// - public IReadOnlyList UserRoles { get; init; } = Array.Empty(); -} diff --git a/src/framework/Application/Extensions/PagedListExtensions.cs b/src/framework/Infrastructure/Extensions/PagedListExtensions.cs similarity index 100% rename from src/framework/Application/Extensions/PagedListExtensions.cs rename to src/framework/Infrastructure/Extensions/PagedListExtensions.cs diff --git a/src/framework/Application/Extensions/RepositoryExtensions.cs b/src/framework/Infrastructure/Extensions/RepositoryExtensions.cs similarity index 100% rename from src/framework/Application/Extensions/RepositoryExtensions.cs rename to src/framework/Infrastructure/Extensions/RepositoryExtensions.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs deleted file mode 100644 index 161fe18e8..000000000 --- a/src/framework/Infrastructure/Identity/Users/Endpoints/AssignRolesToUserEndpoint.cs +++ /dev/null @@ -1,28 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.AssignUserRole; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Identity.Users.Endpoints; -public static class AssignRolesToUserEndpoint -{ - internal static RouteHandlerBuilder MapAssignRolesToUserEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/{id:guid}/roles", async (AssignUserRoleCommand command, - HttpContext context, - string id, - IUserService userService, - CancellationToken cancellationToken) => - { - - var message = await userService.AssignRolesAsync(id, command, cancellationToken); - return Results.Ok(message); - }) - .WithName(nameof(AssignRolesToUserEndpoint)) - .WithSummary("assign roles") - .WithDescription("assign roles"); - } - -} diff --git a/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs b/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs index 78a9b3285..ad59b5ba5 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs @@ -9,12 +9,14 @@ public class CommandDispatcher : ICommandDispatcher public CommandDispatcher(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; - public Task SendAsync(TCommand command, CancellationToken ct = default) - where TCommand : ICommand + public Task SendAsync(ICommand command, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(command); - var handler = _serviceProvider.GetRequiredService>(); - return handler.HandleAsync(command, ct); + var handlerType = typeof(ICommandHandler<,>).MakeGenericType(command.GetType(), typeof(TResponse)); + dynamic handler = _serviceProvider.GetRequiredService(handlerType); + + // dynamic dispatch to call HandleAsync(command, ct) + return handler.HandleAsync((dynamic)command, ct); } } diff --git a/src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs b/src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs index 36c240eb7..68c3606f2 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs @@ -9,12 +9,13 @@ public class QueryDispatcher : IQueryDispatcher public QueryDispatcher(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; - public Task SendAsync(TQuery query, CancellationToken ct = default) - where TQuery : IQuery + public Task SendAsync(IQuery query, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(query); - var handler = _serviceProvider.GetRequiredService>(); - return handler.HandleAsync(query, ct); + var handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResponse)); + dynamic handler = _serviceProvider.GetRequiredService(handlerType); + + return handler.HandleAsync((dynamic)query, ct); } } diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs index a24ac3a64..434e9bdf0 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs @@ -13,12 +13,9 @@ public CommandValidation(ICommandDispatcher inner, IEnumerable SendAsync(TCommand command, CancellationToken ct = default) - where TCommand : ICommand + public async Task SendAsync(ICommand command, CancellationToken ct = default) { - var typedValidators = _validators.OfType>(); - await ValidationHelper.ValidateAsync(command, typedValidators, ct); - - return await _inner.SendAsync(command, ct); + await ValidationHelper.ValidateAsync(command, _validators, ct); + return await _inner.SendAsync(command, ct); } } diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs index 4f69ac2d0..66f9192d3 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs @@ -13,12 +13,9 @@ public QueryValidation(IQueryDispatcher inner, IEnumerable> v _validators = validators; } - public async Task SendAsync(TQuery query, CancellationToken ct = default) - where TQuery : IQuery + public async Task SendAsync(IQuery query, CancellationToken ct = default) { - var typedValidators = _validators.OfType>(); - await ValidationHelper.ValidateAsync(query, typedValidators, ct); - - return await _inner.SendAsync(query, ct); + await ValidationHelper.ValidateAsync(query, _validators, ct); + return await _inner.SendAsync(query, ct); } } diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs index 9a8bd4c3f..496cf9d11 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs @@ -4,16 +4,33 @@ namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; internal static class ValidationHelper { - public static async Task ValidateAsync( - TRequest request, - IEnumerable> validators, - CancellationToken cancellationToken) + public static async Task ValidateAsync(object request, IEnumerable validators, CancellationToken ct = default) { - if (!validators.Any()) return; + var requestType = request.GetType(); + var applicableValidators = validators + .Where(v => v.GetType().GetInterfaces() + .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>) && + i.GetGenericArguments()[0].IsAssignableFrom(requestType))) + .ToList(); - var context = new ValidationContext(request); - var results = await Task.WhenAll(validators.Select(v => v.ValidateAsync(context, cancellationToken))); - var failures = results.SelectMany(r => r.Errors).Where(f => f != null).ToList(); + if (applicableValidators.Count == 0) return; + + var contextType = typeof(ValidationContext<>).MakeGenericType(requestType); + var context = Activator.CreateInstance(contextType, request)!; + + var failures = new List(); + + foreach (var validator in applicableValidators) + { + var validateAsyncMethod = validator.GetType() + .GetMethod("ValidateAsync", new[] { contextType, typeof(CancellationToken) })!; + + var task = (Task) + validateAsyncMethod.Invoke(validator, new[] { context, ct })!; + + var result = await task; + failures.AddRange(result.Errors.Where(f => f != null)); + } if (failures.Count > 0) throw new ValidationException(failures); diff --git a/src/framework/Infrastructure/Modules/IEndpoint.cs b/src/framework/Infrastructure/Modules/IEndpoint.cs new file mode 100644 index 000000000..2e06275fd --- /dev/null +++ b/src/framework/Infrastructure/Modules/IEndpoint.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Infrastructure.Modules; +public interface IEndpoint +{ + RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder endpoints); +} diff --git a/src/framework/Infrastructure/Modules/IEndpointModule.cs b/src/framework/Infrastructure/Modules/IModule.cs similarity index 80% rename from src/framework/Infrastructure/Modules/IEndpointModule.cs rename to src/framework/Infrastructure/Modules/IModule.cs index a88637ddf..912e6860e 100644 --- a/src/framework/Infrastructure/Modules/IEndpointModule.cs +++ b/src/framework/Infrastructure/Modules/IModule.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Infrastructure.Modules; -public interface IEndpointModule : ICoreModule +public interface IModule : ICoreModule { IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints); } \ No newline at end of file diff --git a/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj b/src/framework/Modules/Auditing.Contracts/Auditing.Contracts.csproj similarity index 80% rename from src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj rename to src/framework/Modules/Auditing.Contracts/Auditing.Contracts.csproj index 26b279a6b..5703eb745 100644 --- a/src/framework/Auditing/Auditing.Contracts/Auditing.Contracts.csproj +++ b/src/framework/Modules/Auditing.Contracts/Auditing.Contracts.csproj @@ -6,4 +6,7 @@ + + + diff --git a/src/framework/Modules/Auditing.Contracts/AuditingConstants.cs b/src/framework/Modules/Auditing.Contracts/AuditingConstants.cs new file mode 100644 index 000000000..88b1ae537 --- /dev/null +++ b/src/framework/Modules/Auditing.Contracts/AuditingConstants.cs @@ -0,0 +1,18 @@ +namespace FSH.Framework.Auditing.Contracts; + +public static class AuditingConstants +{ + public const string SchemaName = "auditing"; + public const string ModuleName = "Auditing"; + + public static class Permissions + { + public const string View = "Permissions.Auditing.View"; + } + + public static class Routes + { + public const string Base = "/v1/auditing"; + public const string GetUserLogs = $"{Base}/logs/{{userId:guid}}"; + } +} diff --git a/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs b/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs new file mode 100644 index 000000000..d6fc3bf60 --- /dev/null +++ b/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs @@ -0,0 +1,16 @@ +using FSH.Framework.Auditing.Contracts.Enums; +using System.Collections.ObjectModel; + +namespace FSH.Framework.Auditing.Contracts.Dtos; +public record TrailDto( + Guid Id, + DateTimeOffset DateTime, + Guid UserId, + AuditOperation Operation, + string Description, + string EntityName, + Dictionary KeyValues, + Dictionary OldValues, + Dictionary NewValues, + Collection ModifiedProperties +); \ No newline at end of file diff --git a/src/framework/Auditing/Auditing.Contracts/Enums/AuditOperation.cs b/src/framework/Modules/Auditing.Contracts/Enums/AuditOperation.cs similarity index 100% rename from src/framework/Auditing/Auditing.Contracts/Enums/AuditOperation.cs rename to src/framework/Modules/Auditing.Contracts/Enums/AuditOperation.cs diff --git a/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs b/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs new file mode 100644 index 000000000..e5ccab4fe --- /dev/null +++ b/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs @@ -0,0 +1,14 @@ +using FSH.Framework.Auditing.Contracts.Dtos; +using FSH.Framework.Core.Messaging.Events; + +namespace FSH.Framework.Auditing.Contracts.Events.IntegrationEvents; + +public class AuditPublishedEvent : INotification +{ + public IReadOnlyCollection Trails { get; } + + public AuditPublishedEvent(IReadOnlyCollection trails) + { + Trails = trails; + } +} diff --git a/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs b/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs new file mode 100644 index 000000000..1edab3eaa --- /dev/null +++ b/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Auditing.Contracts.v1.GetUserTrails; +public sealed record GetUserTrailsQuery(Guid UserId) : IQuery; \ No newline at end of file diff --git a/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs b/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs new file mode 100644 index 000000000..8c9a42651 --- /dev/null +++ b/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Auditing.Contracts.Dtos; + +namespace FSH.Framework.Auditing.Contracts.v1.GetUserTrails; +public sealed record GetUserTrailsQueryResponse(IReadOnlyList AuditTrails); \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Auditing.csproj b/src/framework/Modules/Auditing/Auditing.csproj new file mode 100644 index 000000000..d57e0e4d6 --- /dev/null +++ b/src/framework/Modules/Auditing/Auditing.csproj @@ -0,0 +1,18 @@ + + + FSH.Framework.Auditing + FSH.Framework.Auditing + + + net9.0 + enable + enable + + + + + + + + + diff --git a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs b/src/framework/Modules/Auditing/AuditingModule.cs similarity index 80% rename from src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs rename to src/framework/Modules/Auditing/AuditingModule.cs index 79ab48abf..4d4260370 100644 --- a/src/framework/Auditing/Auditing.Endpoints/AuditingModule.cs +++ b/src/framework/Modules/Auditing/AuditingModule.cs @@ -1,5 +1,5 @@ using Asp.Versioning; -using FSH.Framework.Auditing.Endpoints.v1; +using FSH.Framework.Auditing.Features.v1.GetUserTrails; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Modules; using Microsoft.AspNetCore.Builder; @@ -7,14 +7,13 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using System.Reflection; namespace FSH.Framework.Auditing.Endpoints; -public class AuditingModule : IEndpointModule +public class AuditingModule : IModule { public IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config) { - services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); + services.RegisterCommandAndQueryHandlers(typeof(AuditingModule).Assembly); // other registrations return services; @@ -33,7 +32,7 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) .WithOpenApi() .WithApiVersionSet(apiVersionSet); - GetUserTrails.MapEndpoint(group); + GetUserTrailsQueryEndpoint.Map(group); return endpoints; } diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs b/src/framework/Modules/Auditing/Data/AuditingConfiguration.cs similarity index 84% rename from src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs rename to src/framework/Modules/Auditing/Data/AuditingConfiguration.cs index 8bace7411..bd4ca0495 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingConfiguration.cs +++ b/src/framework/Modules/Auditing/Data/AuditingConfiguration.cs @@ -1,9 +1,10 @@ using Finbuckle.MultiTenant; using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Core.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FSH.Framework.Auditing.Infrastructure.Data; +namespace FSH.Framework.Auditing.Data; public class TrailConfig : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) diff --git a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs b/src/framework/Modules/Auditing/Data/AuditingDbContext.cs similarity index 74% rename from src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs rename to src/framework/Modules/Auditing/Data/AuditingDbContext.cs index 03260f924..736ee1701 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Data/AuditingDbContext.cs +++ b/src/framework/Modules/Auditing/Data/AuditingDbContext.cs @@ -1,8 +1,7 @@ -using FSH.Framework.Auditing.Contracts; -using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Auditing.Core.Entities; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Auditing.Infrastructure.Data; +namespace FSH.Framework.Auditing.Data; public class AuditingDbContext : DbContext, IAuditingDbContext { public DbSet Trails { get; set; } @@ -13,4 +12,5 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(typeof(AuditingDbContext).Assembly); } + } diff --git a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs b/src/framework/Modules/Auditing/Data/IAuditingDbContext.cs similarity index 65% rename from src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs rename to src/framework/Modules/Auditing/Data/IAuditingDbContext.cs index 475012522..3d53d252a 100644 --- a/src/framework/Auditing/Auditing.Core/Abstractions/IAuditingDbContext.cs +++ b/src/framework/Modules/Auditing/Data/IAuditingDbContext.cs @@ -1,7 +1,7 @@ -using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Core.Entities; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Auditing.Core.Abstractions; +namespace FSH.Framework.Auditing.Data; public interface IAuditingDbContext { DbSet Trails { get; } diff --git a/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs b/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs similarity index 97% rename from src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs rename to src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs index 199b14e83..33bbce879 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Interceptors/AuditInterceptor.cs +++ b/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Auditing.Contracts; +using FSH.Framework.Auditing.Contracts.DomainEvents; using FSH.Framework.Auditing.Contracts.Enums; -using FSH.Framework.Auditing.Contracts.Events; +using FSH.Framework.Auditing.Features.Entities; using FSH.Framework.Core.Domain; using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.ExecutionContext; @@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; -namespace FSH.Framework.Auditing.Infrastructure.Interceptors; +namespace FSH.Framework.Auditing.Data.Interceptors; public class AuditInterceptor(ICurrentUser currentUser, TimeProvider timeProvider, IEventPublisher publisher) : SaveChangesInterceptor { public override ValueTask SavedChangesAsync(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = default) diff --git a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs b/src/framework/Modules/Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs similarity index 70% rename from src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs rename to src/framework/Modules/Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs index 6f9101a4f..aaca2ed67 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Handlers/AuditPublishedEventHandler.cs +++ b/src/framework/Modules/Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs @@ -1,16 +1,17 @@ -using FSH.Framework.Auditing.Contracts.Events; -using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Auditing.Contracts.Events.IntegrationEvents; +using FSH.Framework.Auditing.Data; using FSH.Framework.Core.Messaging.Events; +using FSH.Modules.Auditing.Core.Mappings; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using System.Diagnostics.CodeAnalysis; -namespace FSH.Framework.Auditing.Infrastructure.Handlers; +namespace FSH.Framework.Auditing.EventHandlers; [SuppressMessage("Performance", "CA1848")] [SuppressMessage("Design", "CA1031")] -public class AuditPublishedEventHandler( - ILogger logger, +public class AuditPublishedIntegrationEventHandler( + ILogger logger, IAuditingDbContext context) : IEventHandler { @@ -21,10 +22,10 @@ public async Task HandleAsync(AuditPublishedEvent notification, CancellationToke logger.LogDebug("No audit trails to persist."); return; } - try { - await context.Trails.AddRangeAsync(notification.Trails, cancellationToken); + var trailEntities = notification.Trails.ToEntityList(); + await context.Trails.AddRangeAsync(trailEntities, cancellationToken); await context.SaveChangesAsync(cancellationToken); logger.LogInformation("Persisted {Count} audit trail(s).", notification.Trails.Count); } diff --git a/src/framework/Modules/Auditing/Features/Entities/Trail.cs b/src/framework/Modules/Auditing/Features/Entities/Trail.cs new file mode 100644 index 000000000..14195b970 --- /dev/null +++ b/src/framework/Modules/Auditing/Features/Entities/Trail.cs @@ -0,0 +1,69 @@ +using FSH.Framework.Auditing.Contracts.Enums; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json; + +namespace FSH.Framework.Auditing.Core.Entities; + +public class Trail +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } + public DateTimeOffset DateTime { get; set; } + public AuditOperation Operation { get; set; } + public string Description { get; set; } = default!; + public string? EntityName { get; set; } + + // Backing fields for JSON storage (persisted) + public string KeyValuesJson { get; private set; } = "{}"; + public string OldValuesJson { get; private set; } = "{}"; + public string NewValuesJson { get; private set; } = "{}"; + public string ModifiedPropertiesJson { get; private set; } = "[]"; + + // Domain-facing properties (not mapped) + [NotMapped] + public IReadOnlyDictionary KeyValues => + DeserializeDict(KeyValuesJson); + + [NotMapped] + public IReadOnlyDictionary OldValues => + DeserializeDict(OldValuesJson); + + [NotMapped] + public IReadOnlyDictionary NewValues => + DeserializeDict(NewValuesJson); + + [NotMapped] + public IReadOnlyCollection ModifiedProperties => + JsonSerializer.Deserialize>(ModifiedPropertiesJson) + ?? []; + + // Setters for domain logic + public void SetKeyValues(Dictionary values) => + KeyValuesJson = Serialize(values); + + public void SetOldValues(Dictionary values) => + OldValuesJson = Serialize(values); + + public void SetNewValues(Dictionary values) => + NewValuesJson = Serialize(values); + + public void SetModifiedProperties(IEnumerable properties) => + ModifiedPropertiesJson = JsonSerializer.Serialize(properties.Distinct().ToList()); + + public void AddModifiedProperty(string property) + { + var props = ModifiedProperties.ToList(); + if (!props.Contains(property)) + props.Add(property); + ModifiedPropertiesJson = JsonSerializer.Serialize(props); + } + + // Helpers + private static Dictionary DeserializeDict(string json) + { + return JsonSerializer.Deserialize>(json) ?? new Dictionary(); + } + + private static string Serialize(object obj) => + JsonSerializer.Serialize(obj); +} diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryEndpoint.cs b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryEndpoint.cs new file mode 100644 index 000000000..c5bcb3e68 --- /dev/null +++ b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryEndpoint.cs @@ -0,0 +1,27 @@ +using FSH.Framework.Auditing.Contracts.v1.GetUserTrails; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Auditing.Features.v1.GetUserTrails; +public static class GetUserTrailsQueryEndpoint +{ + public static RouteHandlerBuilder Map(IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/users/{userId:guid}/trails", async ( + Guid userId, + IQueryDispatcher dispatcher, + CancellationToken cancellationToken) => + { + var query = new GetUserTrailsQuery(userId); + var result = await dispatcher.SendAsync(query, cancellationToken); + return TypedResults.Ok(result); + }) + .WithName(nameof(GetUserTrailsQueryEndpoint)) + .WithSummary("Get user's audit trail details") + .WithDescription("Returns the audit trail details for a specific user.") + .RequirePermission("Permissions.AuditTrails.View"); + } +} diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs new file mode 100644 index 000000000..01d6a8fc3 --- /dev/null +++ b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs @@ -0,0 +1,14 @@ +using FSH.Framework.Auditing.Contracts.v1.GetUserTrails; +using FSH.Framework.Auditing.Services; +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Auditing.Features.v1.GetUserTrails; +internal class GetUserTrailsQueryHandler(IAuditService auditService) + : IQueryHandler +{ + public async Task HandleAsync(GetUserTrailsQuery query, CancellationToken cancellationToken = default) + { + var trails = await auditService.GetUserTrailsAsync(query.UserId); + return new GetUserTrailsQueryResponse(trails); + } +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs new file mode 100644 index 000000000..23cdac918 --- /dev/null +++ b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs @@ -0,0 +1,11 @@ +using FluentValidation; +using FSH.Framework.Auditing.Contracts.v1.GetUserTrails; + +namespace FSH.Framework.Auditing.Features.v1.GetUserTrails; +internal class GetUserTrailsQueryValidator : AbstractValidator +{ + public GetUserTrailsQueryValidator() + { + RuleFor(x => x.UserId).NotEmpty(); + } +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/GlobalSuppressions.cs b/src/framework/Modules/Auditing/GlobalSuppressions.cs new file mode 100644 index 000000000..7b10209aa --- /dev/null +++ b/src/framework/Modules/Auditing/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "", Scope = "member", Target = "~P:FSH.Framework.Auditing.Core.Entities.Trail.KeyValues")] diff --git a/src/framework/Modules/Auditing/Mappings/TrailMappings.cs b/src/framework/Modules/Auditing/Mappings/TrailMappings.cs new file mode 100644 index 000000000..52bcd9f86 --- /dev/null +++ b/src/framework/Modules/Auditing/Mappings/TrailMappings.cs @@ -0,0 +1,54 @@ +using FSH.Framework.Auditing.Contracts.Dtos; +using FSH.Framework.Auditing.Core.Entities; +using System.Collections.ObjectModel; + +namespace FSH.Modules.Auditing.Core.Mappings; + +public static class TrailMappings +{ + public static TrailDto ToDto(this Trail trail) + { + return new( + Id: trail.Id, + DateTime: trail.DateTime, + UserId: trail.UserId, + Operation: trail.Operation, + Description: trail.Description, + EntityName: trail.EntityName ?? string.Empty, + KeyValues: new Dictionary(trail.KeyValues), + OldValues: new Dictionary(trail.OldValues), + NewValues: new Dictionary(trail.NewValues), + ModifiedProperties: new Collection(trail.ModifiedProperties.ToList()) + ); + } + + public static IReadOnlyList ToDtoList(this IEnumerable trails) + { + return trails.Select(t => t.ToDto()).ToList(); + } + + public static Trail ToEntity(this TrailDto dto) + { + var entity = new Trail + { + Id = dto.Id, + DateTime = dto.DateTime, + UserId = dto.UserId, + Operation = dto.Operation, + Description = dto.Description, + EntityName = dto.EntityName + }; + + entity.SetKeyValues(dto.KeyValues); + entity.SetOldValues(dto.OldValues); + entity.SetNewValues(dto.NewValues); + entity.SetModifiedProperties(dto.ModifiedProperties); + + return entity; + } + + public static IReadOnlyList ToEntityList(this IEnumerable dtos) + { + return dtos.Select(dto => dto.ToEntity()).ToList(); + } +} diff --git a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs b/src/framework/Modules/Auditing/Services/AuditService.cs similarity index 51% rename from src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs rename to src/framework/Modules/Auditing/Services/AuditService.cs index a4f285960..510d2b501 100644 --- a/src/framework/Auditing/Auditing.Infrastructure/Services/AuditService.cs +++ b/src/framework/Modules/Auditing/Services/AuditService.cs @@ -1,17 +1,19 @@ -using FSH.Framework.Auditing.Contracts; -using FSH.Framework.Auditing.Core.Abstractions; +using FSH.Framework.Auditing.Contracts.Dtos; +using FSH.Framework.Auditing.Data; +using FSH.Modules.Auditing.Core.Mappings; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Auditing.Infrastructure.Services; +namespace FSH.Framework.Auditing.Services; public class AuditService(IAuditingDbContext context) : IAuditService { - public async Task> GetUserTrailsAsync(Guid userId) + public async Task> GetUserTrailsAsync(Guid userId) { var trails = await context.Trails .Where(a => a.UserId == userId) .OrderByDescending(a => a.DateTime) .Take(250) .ToListAsync(); - return trails; + + return trails.ToDtoList(); } } diff --git a/src/framework/Modules/Auditing/Services/IAuditService.cs b/src/framework/Modules/Auditing/Services/IAuditService.cs new file mode 100644 index 000000000..40cf3608c --- /dev/null +++ b/src/framework/Modules/Auditing/Services/IAuditService.cs @@ -0,0 +1,7 @@ +using FSH.Framework.Auditing.Contracts.Dtos; + +namespace FSH.Framework.Auditing.Services; +public interface IAuditService +{ + Task> GetUserTrailsAsync(Guid userId); +} diff --git a/src/framework/Identity/Identity.Core/Identity.Core.csproj b/src/framework/Modules/Identity/Identity.Core/Identity.Core.csproj similarity index 69% rename from src/framework/Identity/Identity.Core/Identity.Core.csproj rename to src/framework/Modules/Identity/Identity.Core/Identity.Core.csproj index d837ed222..60ee64c12 100644 --- a/src/framework/Identity/Identity.Core/Identity.Core.csproj +++ b/src/framework/Modules/Identity/Identity.Core/Identity.Core.csproj @@ -3,4 +3,7 @@ FSH.Framework.Identity.Core FSH.Framework.Identity.Core + + + diff --git a/src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs b/src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs new file mode 100644 index 000000000..b7281618f --- /dev/null +++ b/src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Identity.Core.Roles; +public class CreateOrUpdateRoleRequest +{ +} diff --git a/src/framework/Identity/Identity.Core/Roles/IRoleService.cs b/src/framework/Modules/Identity/Identity.Core/Roles/IRoleService.cs similarity index 68% rename from src/framework/Identity/Identity.Core/Roles/IRoleService.cs rename to src/framework/Modules/Identity/Identity.Core/Roles/IRoleService.cs index 43339694b..243bc9b73 100644 --- a/src/framework/Identity/Identity.Core/Roles/IRoleService.cs +++ b/src/framework/Modules/Identity/Identity.Core/Roles/IRoleService.cs @@ -4,10 +4,10 @@ public interface IRoleService { Task> GetRolesAsync(); Task GetRoleAsync(string id); - Task CreateOrUpdateRoleAsync(CreateOrUpdateRoleCommand command); + Task CreateOrUpdateRoleAsync(CreateOrUpdateRoleRequest request); Task DeleteRoleAsync(string id); Task GetWithPermissionsAsync(string id, CancellationToken cancellationToken); - Task UpdatePermissionsAsync(UpdatePermissionsCommand request); + Task UpdatePermissionsAsync(UpdatePermissionsRequest request); } diff --git a/src/framework/Identity/Identity.Core/Roles/RoleDto.cs b/src/framework/Modules/Identity/Identity.Core/Roles/RoleDto.cs similarity index 76% rename from src/framework/Identity/Identity.Core/Roles/RoleDto.cs rename to src/framework/Modules/Identity/Identity.Core/Roles/RoleDto.cs index 75ef78631..d026765e1 100644 --- a/src/framework/Identity/Identity.Core/Roles/RoleDto.cs +++ b/src/framework/Modules/Identity/Identity.Core/Roles/RoleDto.cs @@ -5,5 +5,5 @@ public class RoleDto public string Id { get; set; } = default!; public string Name { get; set; } = default!; public string? Description { get; set; } - public List? Permissions { get; set; } + public IReadOnlyCollection? Permissions { get; set; } } diff --git a/src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs b/src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs new file mode 100644 index 000000000..d1ee944a8 --- /dev/null +++ b/src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Identity.Core.Roles; +public class UpdatePermissionsRequest +{ +} diff --git a/src/framework/Identity/Identity.Core/Dtos/UserRoleDetail.cs b/src/framework/Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs similarity index 67% rename from src/framework/Identity/Identity.Core/Dtos/UserRoleDetail.cs rename to src/framework/Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs index 935fd79b6..68314fbf8 100644 --- a/src/framework/Identity/Identity.Core/Dtos/UserRoleDetail.cs +++ b/src/framework/Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs @@ -1,5 +1,5 @@ -namespace FSH.Framework.Core.Identity.Users.Dtos; -public class UserRoleDetail +namespace FSH.Framework.Identity.Core.Roles; +public class UserRoleDetailDto { public string? RoleId { get; set; } public string? RoleName { get; set; } diff --git a/src/framework/Identity/Identity.Core/Tokens/ITokenService.cs b/src/framework/Modules/Identity/Identity.Core/Tokens/ITokenService.cs similarity index 100% rename from src/framework/Identity/Identity.Core/Tokens/ITokenService.cs rename to src/framework/Modules/Identity/Identity.Core/Tokens/ITokenService.cs diff --git a/src/framework/Identity/Identity.Core/Tokens/TokenDto.cs b/src/framework/Modules/Identity/Identity.Core/Tokens/TokenDto.cs similarity index 100% rename from src/framework/Identity/Identity.Core/Tokens/TokenDto.cs rename to src/framework/Modules/Identity/Identity.Core/Tokens/TokenDto.cs diff --git a/src/framework/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs b/src/framework/Modules/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs similarity index 83% rename from src/framework/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs rename to src/framework/Modules/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs index afcbfee2f..bf4e81b66 100644 --- a/src/framework/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs +++ b/src/framework/Modules/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs @@ -1,2 +1,2 @@ namespace FSH.Framework.Identity.Core.Tokens; -public record TokenGenerationRequest(string Email, string Password); +public record TokenGenerationRequest(string Email, string Password, string IpAddress); diff --git a/src/framework/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs b/src/framework/Modules/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs similarity index 100% rename from src/framework/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs rename to src/framework/Modules/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs diff --git a/src/framework/Identity/Identity.Core/Users/ICurrentUserInitializer.cs b/src/framework/Modules/Identity/Identity.Core/Users/ICurrentUserInitializer.cs similarity index 100% rename from src/framework/Identity/Identity.Core/Users/ICurrentUserInitializer.cs rename to src/framework/Modules/Identity/Identity.Core/Users/ICurrentUserInitializer.cs diff --git a/src/framework/Identity/Identity.Core/Users/IUserService.cs b/src/framework/Modules/Identity/Identity.Core/Users/IUserService.cs similarity index 74% rename from src/framework/Identity/Identity.Core/Users/IUserService.cs rename to src/framework/Modules/Identity/Identity.Core/Users/IUserService.cs index e0083178a..a2a68e48c 100644 --- a/src/framework/Identity/Identity.Core/Users/IUserService.cs +++ b/src/framework/Modules/Identity/Identity.Core/Users/IUserService.cs @@ -1,6 +1,5 @@ -using System.Security.Claims; -using FSH.Framework.Core.Identity.Users.Dtos; -using FSH.Framework.Identity.Core.Dtos; +using FSH.Framework.Identity.Core.Roles; +using System.Security.Claims; namespace FSH.Framework.Identity.Core.Users; public interface IUserService @@ -8,9 +7,9 @@ public interface IUserService Task ExistsWithNameAsync(string name); Task ExistsWithEmailAsync(string email, string? exceptId = null); Task ExistsWithPhoneNumberAsync(string phoneNumber, string? exceptId = null); - Task> GetListAsync(CancellationToken cancellationToken); + Task> GetListAsync(CancellationToken cancellationToken); Task GetCountAsync(CancellationToken cancellationToken); - Task GetAsync(string userId, CancellationToken cancellationToken); + Task GetAsync(string userId, CancellationToken cancellationToken); Task ToggleStatusAsync(ToggleUserStatusCommand request, CancellationToken cancellationToken); Task GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal); Task RegisterAsync(RegisterUserCommand request, string origin, CancellationToken cancellationToken); @@ -28,6 +27,6 @@ public interface IUserService Task?> GetPermissionsAsync(string userId, CancellationToken cancellationToken); Task ChangePasswordAsync(ChangePasswordCommand request, string userId); - Task AssignRolesAsync(string userId, AssignUserRoleCommand request, CancellationToken cancellationToken); - Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken); + Task AssignRolesAsync(string userId, IReadOnlyList userRoles, CancellationToken cancellationToken); + Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken); } diff --git a/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs b/src/framework/Modules/Identity/Identity.Core/Users/UserDetailDto.cs similarity index 83% rename from src/framework/Identity/Identity.Core/Dtos/UserDetail.cs rename to src/framework/Modules/Identity/Identity.Core/Users/UserDetailDto.cs index 4888e6031..1044991ed 100644 --- a/src/framework/Identity/Identity.Core/Dtos/UserDetail.cs +++ b/src/framework/Modules/Identity/Identity.Core/Users/UserDetailDto.cs @@ -1,5 +1,5 @@ -namespace FSH.Framework.Identity.Core.Dtos; -public class UserDetail +namespace FSH.Framework.Identity.Core.Users; +public class UserDetailDto { public string? Id { get; set; } diff --git a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj b/src/framework/Modules/Identity/Identity.Endpoints/Identity.Endpoints.csproj similarity index 80% rename from src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj rename to src/framework/Modules/Identity/Identity.Endpoints/Identity.Endpoints.csproj index 587355065..7fef10583 100644 --- a/src/framework/Identity/Identity.Endpoints/Identity.Endpoints.csproj +++ b/src/framework/Modules/Identity/Identity.Endpoints/Identity.Endpoints.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs similarity index 95% rename from src/framework/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs index a73629eb0..e9aa43a68 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs +++ b/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs @@ -27,7 +27,7 @@ internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpo HttpContext context, CancellationToken cancellationToken) => { - var result = await dispatcher.SendAsync(command, cancellationToken); + var result = await dispatcher.SendAsync(command, cancellationToken); return TypedResults.Ok(result); }) .WithName(nameof(RefreshToken)) diff --git a/src/framework/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs similarity index 95% rename from src/framework/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs index b8081e27e..415919b8b 100644 --- a/src/framework/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs +++ b/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs @@ -34,7 +34,7 @@ internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpo HttpContext context, CancellationToken cancellationToken) => { - var result = await dispatcher.SendAsync(command, cancellationToken); + var result = await dispatcher.SendAsync(command, cancellationToken); return TypedResults.Ok(result); }) .WithName(nameof(TokenGeneration)) diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs new file mode 100644 index 000000000..4c50ffc2d --- /dev/null +++ b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs @@ -0,0 +1,36 @@ +using FSH.Framework.Core.Identity.Users.Dtos; +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Core.Users; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Identity.Endpoints.v1.Users; +public static class AssignUserRoles +{ + public class Command : ICommand + { + public required string UserId { get; init; } + public IReadOnlyList UserRoles { get; init; } = Array.Empty(); + } + internal class Handler(IUserService _userService) : ICommandHandler + { + public async Task HandleAsync(Command request, CancellationToken cancellationToken = default) => + await _userService.AssignRolesAsync(request.UserId, request.UserRoles, cancellationToken); + } + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/{id:guid}/roles", async (Command command, + HttpContext context, + string id, + ICommandDispatcher dispatcher, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync(command, cancellationToken); + return Results.Ok(result); + }) + .WithName(nameof(AssignUserRoles)) + .WithSummary("assign roles") + .WithDescription("assign roles"); + } +} diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs diff --git a/src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs similarity index 100% rename from src/framework/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs rename to src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Modules/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj similarity index 75% rename from src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj rename to src/framework/Modules/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index 31a418ff5..e3e60747c 100644 --- a/src/framework/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/src/framework/Modules/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -4,9 +4,9 @@ FSH.Framework.Identity.Infrastructure - - - + + + diff --git a/src/framework/Identity/Identity.Infrastructure/IdentityConstants.cs b/src/framework/Modules/Identity/Identity.Infrastructure/IdentityConstants.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/IdentityConstants.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/IdentityConstants.cs diff --git a/src/framework/Identity/Identity.Infrastructure/JwtOptions.cs b/src/framework/Modules/Identity/Identity.Infrastructure/JwtOptions.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/JwtOptions.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/JwtOptions.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Roles/FshRole.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Roles/FshRole.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Roles/FshRole.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Roles/FshRole.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Tokens/TokenService.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Tokens/TokenService.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Tokens/TokenService.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Tokens/TokenService.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Users/CurrentUserService.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Users/CurrentUserService.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Users/CurrentUserService.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Users/CurrentUserService.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Users/FshUser.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Users/FshUser.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Users/FshUser.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Users/FshUser.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Users/UserService.Password.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Password.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Users/UserService.Password.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Password.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs similarity index 100% rename from src/framework/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs diff --git a/src/framework/Identity/Identity.Infrastructure/Users/UserService.cs b/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.cs similarity index 95% rename from src/framework/Identity/Identity.Infrastructure/Users/UserService.cs rename to src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.cs index 5040fb33e..fc5168004 100644 --- a/src/framework/Identity/Identity.Infrastructure/Users/UserService.cs +++ b/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.cs @@ -7,7 +7,7 @@ using FSH.Framework.Core.Jobs; using FSH.Framework.Core.Mail; using FSH.Framework.Core.Storage; -using FSH.Framework.Identity.Core.Dtos; +using FSH.Framework.Identity.Core.Roles; using FSH.Framework.Identity.Core.Users; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; @@ -79,7 +79,7 @@ public async Task ExistsWithPhoneNumberAsync(string phoneNumber, string? e return await userManager.Users.FirstOrDefaultAsync(x => x.PhoneNumber == phoneNumber) is FshUser user && user.Id != exceptId; } - public async Task GetAsync(string userId, CancellationToken cancellationToken) + public async Task GetAsync(string userId, CancellationToken cancellationToken) { var user = await userManager.Users .AsNoTracking() @@ -88,7 +88,7 @@ public async Task GetAsync(string userId, CancellationToken cancella _ = user ?? throw new NotFoundException("user not found"); - return new UserDetail + return new UserDetailDto { Id = user.Id, Email = user.Email, @@ -103,13 +103,13 @@ public async Task GetAsync(string userId, CancellationToken cancella public Task GetCountAsync(CancellationToken cancellationToken) => userManager.Users.AsNoTracking().CountAsync(cancellationToken); - public async Task> GetListAsync(CancellationToken cancellationToken) + public async Task> GetListAsync(CancellationToken cancellationToken) { var users = await userManager.Users.AsNoTracking().ToListAsync(cancellationToken); - var result = new List(users.Count); + var result = new List(users.Count); foreach (var user in users) { - result.Add(new UserDetail + result.Add(new UserDetailDto { Id = user.Id, Email = user.Email, @@ -305,9 +305,9 @@ public async Task AssignRolesAsync(string userId, AssignUserRoleCommand } - public async Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken) + public async Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken) { - var userRoles = new List(); + var userRoles = new List(); var user = await userManager.FindByIdAsync(userId); if (user is null) throw new NotFoundException("user not found"); @@ -315,7 +315,7 @@ public async Task> GetUserRolesAsync(string userId, Cancell if (roles is null) throw new NotFoundException("roles not found"); foreach (var role in roles) { - userRoles.Add(new UserRoleDetail + userRoles.Add(new UserRoleDetailDto { RoleId = role.Id, RoleName = role.Name, diff --git a/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj b/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj new file mode 100644 index 000000000..90ca89d4c --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj @@ -0,0 +1,12 @@ + + + FSH.Framework.Tenant.Contracts + FSH.Framework.Tenant.Contracts + + + net9.0 + enable + enable + + + diff --git a/src/framework/Modules/Tenant.Contracts/TenantConstants.cs b/src/framework/Modules/Tenant.Contracts/TenantConstants.cs new file mode 100644 index 000000000..1a979ed35 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/TenantConstants.cs @@ -0,0 +1,4 @@ +namespace Tenant.Contracts; +public static class TenantConstants +{ +} diff --git a/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs b/src/framework/Modules/Tenant/Data/TenantDbContext.cs similarity index 93% rename from src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs rename to src/framework/Modules/Tenant/Data/TenantDbContext.cs index de189da45..243eceecf 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Data/TenantDbContext.cs +++ b/src/framework/Modules/Tenant/Data/TenantDbContext.cs @@ -2,7 +2,7 @@ using FSH.Framework.Shared.Multitenancy; using Microsoft.EntityFrameworkCore; -namespace FSH.Framework.Tenant.Infrastructure.Data; +namespace FSH.Framework.Tenant.Data; public class TenantDbContext : EFCoreStoreDbContext { public const string Schema = "tenant"; diff --git a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs b/src/framework/Modules/Tenant/Extensions.cs similarity index 97% rename from src/framework/Tenant/Tenant.Infrastructure/Extensions.cs rename to src/framework/Modules/Tenant/Extensions.cs index 1e51a785a..14074333c 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/Extensions.cs +++ b/src/framework/Modules/Tenant/Extensions.cs @@ -6,14 +6,14 @@ using FSH.Framework.Infrastructure.Persistence.Services; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; -using FSH.Framework.Tenant.Core.Abstractions; -using FSH.Framework.Tenant.Infrastructure.Data; +using FSH.Framework.Tenant.Data; +using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -namespace FSH.Framework.Tenant.Infrastructure; +namespace FSH.Framework.Tenant; internal static class Extensions { public static IServiceCollection ConfigureMultitenancy(this IServiceCollection services) diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/ActivateTenant.cs b/src/framework/Modules/Tenant/Features/v1/ActivateTenant.cs similarity index 89% rename from src/framework/Tenant/Tenant.Endpoints/v1/ActivateTenant.cs rename to src/framework/Modules/Tenant/Features/v1/ActivateTenant.cs index 2f3ae225e..d185f2199 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/ActivateTenant.cs +++ b/src/framework/Modules/Tenant/Features/v1/ActivateTenant.cs @@ -1,12 +1,12 @@ using FluentValidation; using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Tenant.Endpoints.v1; +namespace FSH.Framework.Tenant.Features.v1; public static class ActivateTenant { public sealed record Command(string TenantId) : ICommand; @@ -28,7 +28,7 @@ public async Task HandleAsync(Command command, CancellationToken cance internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/{id}/activate", async (ICommandDispatcher dispatcher, string id) - => await dispatcher.SendAsync(new Command(id))) + => await dispatcher.SendAsync(new Command(id))) .WithName(nameof(ActivateTenant)) .WithSummary("activate tenant") .RequirePermission("Permissions.Tenants.Update") diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant.cs similarity index 94% rename from src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs rename to src/framework/Modules/Tenant/Features/v1/CreateTenant.cs index 725b72830..14e56a9ca 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/CreateTenant.cs +++ b/src/framework/Modules/Tenant/Features/v1/CreateTenant.cs @@ -2,12 +2,12 @@ using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Core.Persistence; using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Tenant.Endpoints.v1; +namespace FSH.Framework.Tenant.Features.v1; public static class CreateTenant { public sealed record Command(string Id, string Name, string? ConnectionString, string AdminEmail, string? Issuer) : ICommand; @@ -38,7 +38,7 @@ public Validator(ITenantService tenantService, IConnectionStringValidator connec internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/", async (ICommandDispatcher dispatcher, Command command) - => await dispatcher.SendAsync(command)) + => await dispatcher.SendAsync(command)) .WithName(nameof(ActivateTenant)) .WithSummary("activate tenant") .RequirePermission("Permissions.Tenants.Create") diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenant.cs b/src/framework/Modules/Tenant/Features/v1/DisableTenant.cs similarity index 89% rename from src/framework/Tenant/Tenant.Endpoints/v1/DisableTenant.cs rename to src/framework/Modules/Tenant/Features/v1/DisableTenant.cs index b65fb8d84..9ce3e5e4d 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/DisableTenant.cs +++ b/src/framework/Modules/Tenant/Features/v1/DisableTenant.cs @@ -1,12 +1,12 @@ using FluentValidation; using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Tenant.Endpoints.v1; +namespace FSH.Framework.Tenant.Features.v1; public static class DisableTenant { public sealed record Command(string TenantId) : ICommand; @@ -20,7 +20,7 @@ public DisableTenantValidator() => internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/{id}/deactivate", (ICommandDispatcher dispatcher, string id) - => dispatcher.SendAsync(new Command(id))) + => dispatcher.SendAsync(new Command(id))) .WithName(nameof(DisableTenant)) .WithSummary("activate tenant") .RequirePermission("Permissions.Tenants.Update") diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantById.cs b/src/framework/Modules/Tenant/Features/v1/GetTenantById.cs similarity index 83% rename from src/framework/Tenant/Tenant.Endpoints/v1/GetTenantById.cs rename to src/framework/Modules/Tenant/Features/v1/GetTenantById.cs index 26742cdc9..bfe48d3c9 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenantById.cs +++ b/src/framework/Modules/Tenant/Features/v1/GetTenantById.cs @@ -1,11 +1,11 @@ using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; +namespace FSH.Framework.Tenant.Features.v1; public static class GetTenantById { public sealed record Query(string TenantId) : IQuery; @@ -22,16 +22,18 @@ public class Response internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapGet("/{id}", (IQueryDispatcher dispatcher, string id) - => dispatcher.SendAsync(new Query(id))) + => dispatcher.SendAsync(new Query(id))) .WithName(nameof(GetTenantById)) .WithSummary("get tenant by id") .RequirePermission("Permissions.Tenants.View") .WithDescription("get tenant by id"); } - public sealed class Handler(ITenantService service) : IQueryHandler + public sealed class Handler(ITenantService service, IQueryDispatcher dispatcher) : IQueryHandler { public async Task HandleAsync(Query query, CancellationToken cancellationToken = default) { + + var data = await dispatcher.SendAsync(new Query(query.TenantId), cancellationToken); var tenant = await service.GetByIdAsync(query.TenantId); return new Response() { diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenants.cs b/src/framework/Modules/Tenant/Features/v1/GetTenants.cs similarity index 86% rename from src/framework/Tenant/Tenant.Endpoints/v1/GetTenants.cs rename to src/framework/Modules/Tenant/Features/v1/GetTenants.cs index 17a977783..f5afcb536 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/GetTenants.cs +++ b/src/framework/Modules/Tenant/Features/v1/GetTenants.cs @@ -1,13 +1,12 @@ using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Infrastructure.Tenant.Endpoints; using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Tenant.Services; using Mapster; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Tenant.Endpoints.v1; +namespace FSH.Framework.Tenant.Features.v1; public static class GetTenants { public sealed class Query : IQuery; @@ -17,7 +16,7 @@ public sealed class Response } public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapGet("/", (IQueryDispatcher dispatcher) => dispatcher.SendAsync(new Query())) + return endpoints.MapGet("/", (IQueryDispatcher dispatcher) => dispatcher.SendAsync(new Query())) .WithName(nameof(GetTenants)) .WithSummary("get tenants") .RequirePermission("Permissions.Tenants.View") diff --git a/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscription.cs b/src/framework/Modules/Tenant/Features/v1/UpgradeSubscription.cs similarity index 71% rename from src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscription.cs rename to src/framework/Modules/Tenant/Features/v1/UpgradeSubscription.cs index f66d8f03d..7aa3be740 100644 --- a/src/framework/Tenant/Tenant.Endpoints/v1/UpgradeSubscription.cs +++ b/src/framework/Modules/Tenant/Features/v1/UpgradeSubscription.cs @@ -1,12 +1,12 @@ using FluentValidation; using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Core.Abstractions; +using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Infrastructure.Tenant.Endpoints; +namespace FSH.Framework.Tenant.Features.v1; public static class UpgradeSubscription { @@ -20,15 +20,14 @@ public Validator() RuleFor(t => t.ExtendedExpiryDate).GreaterThan(DateTime.UtcNow); } } - - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/upgrade", (Command command, ICommandDispatcher dispatcher) => dispatcher.SendAsync(command)) - .WithName(nameof(UpgradeSubscription)) - .WithSummary("upgrade tenant subscription") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("upgrade tenant subscription"); + return endpoints.MapPost("/upgrade", (Command command, ICommandDispatcher dispatcher) + => dispatcher.SendAsync(command)) + .WithName(nameof(UpgradeSubscription)) + .WithSummary("upgrade tenant subscription") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("upgrade tenant subscription"); } public class Handler(ITenantService service) : ICommandHandler { diff --git a/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs b/src/framework/Modules/Tenant/Services/ITenantService.cs similarity index 87% rename from src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs rename to src/framework/Modules/Tenant/Services/ITenantService.cs index 8f5151b03..a23c58cd7 100644 --- a/src/framework/Tenant/Tenant.Core/Abstractions/ITenantService.cs +++ b/src/framework/Modules/Tenant/Services/ITenantService.cs @@ -1,6 +1,4 @@ -using FSH.Framework.Core.Tenant; - -namespace FSH.Framework.Tenant.Core.Abstractions; +namespace FSH.Framework.Tenant.Services; public interface ITenantService { diff --git a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs b/src/framework/Modules/Tenant/Services/TenantService.cs similarity index 97% rename from src/framework/Tenant/Tenant.Infrastructure/TenantService.cs rename to src/framework/Modules/Tenant/Services/TenantService.cs index 5fa4e920f..42b5362fc 100644 --- a/src/framework/Tenant/Tenant.Infrastructure/TenantService.cs +++ b/src/framework/Modules/Tenant/Services/TenantService.cs @@ -2,14 +2,12 @@ using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Persistence; -using FSH.Framework.Core.Tenant; using FSH.Framework.Shared.Multitenancy; -using FSH.Framework.Tenant.Core.Abstractions; using Mapster; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -namespace FSH.Framework.Tenant.Infrastructure; +namespace FSH.Framework.Tenant.Services; public sealed class TenantService : ITenantService { diff --git a/src/framework/Modules/Tenant/Tenant.csproj b/src/framework/Modules/Tenant/Tenant.csproj new file mode 100644 index 000000000..689a1bc2d --- /dev/null +++ b/src/framework/Modules/Tenant/Tenant.csproj @@ -0,0 +1,16 @@ + + + FSH.Framework.Tenant + FSH.Framework.Tenant + + + net9.0 + enable + enable + + + + + + + diff --git a/src/framework/Tenant/Tenant.Core/TenantDetail.cs b/src/framework/Modules/Tenant/TenantDetail.cs similarity index 89% rename from src/framework/Tenant/Tenant.Core/TenantDetail.cs rename to src/framework/Modules/Tenant/TenantDetail.cs index da1ecb726..7b875526b 100644 --- a/src/framework/Tenant/Tenant.Core/TenantDetail.cs +++ b/src/framework/Modules/Tenant/TenantDetail.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Tenant; +namespace FSH.Framework.Tenant; public class TenantDetail { public string Id { get; set; } = default!; diff --git a/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs b/src/framework/Modules/Tenant/TenantModule.cs similarity index 88% rename from src/framework/Tenant/Tenant.Endpoints/TenantModule.cs rename to src/framework/Modules/Tenant/TenantModule.cs index fe76ae3d3..ec56c898f 100644 --- a/src/framework/Tenant/Tenant.Endpoints/TenantModule.cs +++ b/src/framework/Modules/Tenant/TenantModule.cs @@ -1,8 +1,7 @@ using Asp.Versioning; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Modules; -using FSH.Framework.Infrastructure.Tenant.Endpoints; -using FSH.Framework.Tenant.Endpoints.v1; +using FSH.Framework.Tenant.Features.v1; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -10,8 +9,8 @@ using Microsoft.Extensions.DependencyInjection; using System.Reflection; -namespace FSH.Framework.Tenant.Endpoints; -public class TenantModule : IEndpointModule +namespace FSH.Framework.Tenant; +public class TenantModule : IModule { public IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config) { diff --git a/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj b/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj deleted file mode 100644 index 5c4f65e91..000000000 --- a/src/framework/Tenant/Tenant.Core/Tenant.Core.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - FSH.Framework.Tenant.Core - FSH.Framework.Tenant.Core - - - - - - diff --git a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj b/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj deleted file mode 100644 index 526fd1b38..000000000 --- a/src/framework/Tenant/Tenant.Endpoints/Tenant.Endpoints.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - FSH.Framework.Tenant.Endpoints - FSH.Framework.Tenant.Endpoints - - - - - - - - - - - - - - diff --git a/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj b/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj deleted file mode 100644 index 5ededb759..000000000 --- a/src/framework/Tenant/Tenant.Infrastructure/Tenant.Infrastructure.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - FSH.Framework.Tenant.Infrastructure - FSH.Framework.Tenant.Infrastructure - - - - - - - - - - - - - From fcfa1c9349d1f47ac2005b7f4e102774976b302c Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Sat, 12 Apr 2025 14:03:49 +0530 Subject: [PATCH 25/54] cleanup tenants --- src/framework/Core/Domain/BaseEntity.cs | 4 +- .../Core/Domain/Contracts/IEntity.cs | 2 +- .../Events/{DomainEvent.cs => AppEvent.cs} | 2 +- .../Events/{IDomainEvent.cs => IEvent.cs} | 2 +- .../Core/Messaging/Events/IEventHandler.cs | 2 +- .../Core/Messaging/Events/IEventPublisher.cs | 4 +- .../Infrastructure/Modules/IEndpoint.cs | 8 --- .../Modules/Auditing/AuditingModule.cs | 2 +- ...ryEndpoint.cs => GetUserTrailsEndpoint.cs} | 6 +- .../Modules/Auditing/GlobalSuppressions.cs | 8 --- .../Dtos/TenantDto.cs} | 6 +- .../Tenant.Contracts/Tenant.Contracts.csproj | 3 + .../ActivateTenant/ActivateTenantCommand.cs | 4 ++ .../ActivateTenantCommandResponse.cs | 2 + .../v1/CreateTenant/CreateTenantCommand.cs | 9 +++ .../CreateTenantCommandResponse.cs | 2 + .../v1/DisableTenant/DisableTenantCommand.cs | 4 ++ .../DisableTenantCommandResponse.cs | 2 + .../v1/GetTenantById/GetTenantByIdQuery.cs | 4 ++ .../GetTenantByIdQueryResponse.cs | 4 ++ .../v1/GetTenants/GetTenantsQuery.cs | 4 ++ .../v1/GetTenants/GetTenantsQueryResponse.cs | 4 ++ .../v1/UpgradeTenant/UpgradeTenantCommand.cs | 5 ++ .../UpgradeTenantCommandResponse.cs | 2 + .../Tenant/Features/v1/ActivateTenant.cs | 37 ----------- .../ActivateTenantCommandHandler.cs | 16 +++++ .../ActivateTenantCommandValidator.cs | 10 +++ .../ActivateTenant/ActivateTenantEndpoint.cs | 20 ++++++ .../Tenant/Features/v1/CreateTenant.cs | 61 ------------------- .../CreateTenantCommandHandler.cs | 21 +++++++ .../CreateTenantCommandValidator.cs | 29 +++++++++ .../v1/CreateTenant/CreateTenantEndpoint.cs | 20 ++++++ .../Tenant/Features/v1/DisableTenant.cs | 38 ------------ .../DisableTenantCommandHandler.cs | 16 +++++ .../DisableTenantCommandValidator.cs | 10 +++ .../v1/DisableTenant/DisableTenantEndpoint.cs | 20 ++++++ .../Tenant/Features/v1/GetTenantById.cs | 51 ---------------- .../v1/GetTenantById/GetTenantByIdEndpoint.cs | 20 ++++++ .../GetTenantByIdQueryHandler.cs | 17 ++++++ .../Modules/Tenant/Features/v1/GetTenants.cs | 37 ----------- .../v1/GetTenants/GetTenantsEndpoint.cs | 20 ++++++ .../v1/GetTenants/GetTenantsQueryHandler.cs | 17 ++++++ .../Tenant/Features/v1/UpgradeSubscription.cs | 41 ------------- .../UpgradeTenantCommandHandler.cs | 16 +++++ .../UpgradeTenantCommandValidator.cs | 12 ++++ .../v1/UpgradeTenant/UpgradeTenantEndpoint.cs | 20 ++++++ .../Modules/Tenant/Services/ITenantService.cs | 8 ++- .../Modules/Tenant/Services/TenantService.cs | 9 +-- src/framework/Modules/Tenant/Tenant.csproj | 4 ++ src/framework/Modules/Tenant/TenantModule.cs | 19 +++--- 50 files changed, 374 insertions(+), 310 deletions(-) rename src/framework/Core/Messaging/Events/{DomainEvent.cs => AppEvent.cs} (71%) rename src/framework/Core/Messaging/Events/{IDomainEvent.cs => IEvent.cs} (64%) delete mode 100644 src/framework/Infrastructure/Modules/IEndpoint.cs rename src/framework/Modules/Auditing/Features/v1/GetUserTrails/{GetUserTrailsQueryEndpoint.cs => GetUserTrailsEndpoint.cs} (83%) delete mode 100644 src/framework/Modules/Auditing/GlobalSuppressions.cs rename src/framework/Modules/{Tenant/TenantDetail.cs => Tenant.Contracts/Dtos/TenantDto.cs} (80%) create mode 100644 src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs create mode 100644 src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs delete mode 100644 src/framework/Modules/Tenant/Features/v1/ActivateTenant.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs delete mode 100644 src/framework/Modules/Tenant/Features/v1/CreateTenant.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs delete mode 100644 src/framework/Modules/Tenant/Features/v1/DisableTenant.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs delete mode 100644 src/framework/Modules/Tenant/Features/v1/GetTenantById.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs delete mode 100644 src/framework/Modules/Tenant/Features/v1/GetTenants.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs delete mode 100644 src/framework/Modules/Tenant/Features/v1/UpgradeSubscription.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs create mode 100644 src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs diff --git a/src/framework/Core/Domain/BaseEntity.cs b/src/framework/Core/Domain/BaseEntity.cs index 7b562d2f4..acc8ad24e 100644 --- a/src/framework/Core/Domain/BaseEntity.cs +++ b/src/framework/Core/Domain/BaseEntity.cs @@ -9,8 +9,8 @@ public abstract class BaseEntity : IEntity { public TId Id { get; protected init; } = default!; [NotMapped] - public Collection DomainEvents { get; } = new Collection(); - public void QueueDomainEvent(DomainEvent @event) + public Collection DomainEvents { get; } = new Collection(); + public void QueueDomainEvent(AppEvent @event) { if (!DomainEvents.Contains(@event)) DomainEvents.Add(@event); diff --git a/src/framework/Core/Domain/Contracts/IEntity.cs b/src/framework/Core/Domain/Contracts/IEntity.cs index f6e19a619..67c24d978 100644 --- a/src/framework/Core/Domain/Contracts/IEntity.cs +++ b/src/framework/Core/Domain/Contracts/IEntity.cs @@ -5,7 +5,7 @@ namespace FSH.Framework.Core.Domain.Contracts; public interface IEntity { - Collection DomainEvents { get; } + Collection DomainEvents { get; } } public interface IEntity : IEntity diff --git a/src/framework/Core/Messaging/Events/DomainEvent.cs b/src/framework/Core/Messaging/Events/AppEvent.cs similarity index 71% rename from src/framework/Core/Messaging/Events/DomainEvent.cs rename to src/framework/Core/Messaging/Events/AppEvent.cs index b3c721d34..e59532448 100644 --- a/src/framework/Core/Messaging/Events/DomainEvent.cs +++ b/src/framework/Core/Messaging/Events/AppEvent.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Core.Messaging.Events; -public abstract record DomainEvent : IDomainEvent +public abstract record AppEvent : IEvent { public DateTime RaisedOn { get; protected set; } = DateTime.UtcNow; } diff --git a/src/framework/Core/Messaging/Events/IDomainEvent.cs b/src/framework/Core/Messaging/Events/IEvent.cs similarity index 64% rename from src/framework/Core/Messaging/Events/IDomainEvent.cs rename to src/framework/Core/Messaging/Events/IEvent.cs index 2ff120db6..03a34c203 100644 --- a/src/framework/Core/Messaging/Events/IDomainEvent.cs +++ b/src/framework/Core/Messaging/Events/IEvent.cs @@ -1,4 +1,4 @@ namespace FSH.Framework.Core.Messaging.Events; -public interface IDomainEvent +public interface IEvent { } diff --git a/src/framework/Core/Messaging/Events/IEventHandler.cs b/src/framework/Core/Messaging/Events/IEventHandler.cs index 88e581319..e01700899 100644 --- a/src/framework/Core/Messaging/Events/IEventHandler.cs +++ b/src/framework/Core/Messaging/Events/IEventHandler.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Core.Messaging.Events; -public interface IEventHandler +public interface IEventHandler where TEvent : IEvent { Task HandleAsync(TEvent appEvent, CancellationToken cancellationToken = default); } diff --git a/src/framework/Core/Messaging/Events/IEventPublisher.cs b/src/framework/Core/Messaging/Events/IEventPublisher.cs index 004828325..9cdfea35d 100644 --- a/src/framework/Core/Messaging/Events/IEventPublisher.cs +++ b/src/framework/Core/Messaging/Events/IEventPublisher.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Core.Messaging.Events; -public interface IEventPublisher +public interface IEventPublisher where TEvent : IEvent { - Task PublishAsync(TEvent appEvent, CancellationToken cancellationToken = default); + Task PublishAsync(TEvent appEvent, CancellationToken cancellationToken = default); } diff --git a/src/framework/Infrastructure/Modules/IEndpoint.cs b/src/framework/Infrastructure/Modules/IEndpoint.cs deleted file mode 100644 index 2e06275fd..000000000 --- a/src/framework/Infrastructure/Modules/IEndpoint.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Modules; -public interface IEndpoint -{ - RouteHandlerBuilder MapEndpoint(IEndpointRouteBuilder endpoints); -} diff --git a/src/framework/Modules/Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/AuditingModule.cs index 4d4260370..9507ced59 100644 --- a/src/framework/Modules/Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/AuditingModule.cs @@ -32,7 +32,7 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) .WithOpenApi() .WithApiVersionSet(apiVersionSet); - GetUserTrailsQueryEndpoint.Map(group); + GetUserTrailsEndpoint.Map(group); return endpoints; } diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryEndpoint.cs b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs similarity index 83% rename from src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryEndpoint.cs rename to src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs index c5bcb3e68..378291a69 100644 --- a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryEndpoint.cs +++ b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs @@ -6,9 +6,9 @@ using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Auditing.Features.v1.GetUserTrails; -public static class GetUserTrailsQueryEndpoint +public static class GetUserTrailsEndpoint { - public static RouteHandlerBuilder Map(IEndpointRouteBuilder endpoints) + public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { return endpoints.MapGet("/users/{userId:guid}/trails", async ( Guid userId, @@ -19,7 +19,7 @@ public static RouteHandlerBuilder Map(IEndpointRouteBuilder endpoints) var result = await dispatcher.SendAsync(query, cancellationToken); return TypedResults.Ok(result); }) - .WithName(nameof(GetUserTrailsQueryEndpoint)) + .WithName(nameof(GetUserTrailsEndpoint)) .WithSummary("Get user's audit trail details") .WithDescription("Returns the audit trail details for a specific user.") .RequirePermission("Permissions.AuditTrails.View"); diff --git a/src/framework/Modules/Auditing/GlobalSuppressions.cs b/src/framework/Modules/Auditing/GlobalSuppressions.cs deleted file mode 100644 index 7b10209aa..000000000 --- a/src/framework/Modules/Auditing/GlobalSuppressions.cs +++ /dev/null @@ -1,8 +0,0 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "", Scope = "member", Target = "~P:FSH.Framework.Auditing.Core.Entities.Trail.KeyValues")] diff --git a/src/framework/Modules/Tenant/TenantDetail.cs b/src/framework/Modules/Tenant.Contracts/Dtos/TenantDto.cs similarity index 80% rename from src/framework/Modules/Tenant/TenantDetail.cs rename to src/framework/Modules/Tenant.Contracts/Dtos/TenantDto.cs index 7b875526b..908f69d39 100644 --- a/src/framework/Modules/Tenant/TenantDetail.cs +++ b/src/framework/Modules/Tenant.Contracts/Dtos/TenantDto.cs @@ -1,5 +1,5 @@ -namespace FSH.Framework.Tenant; -public class TenantDetail +namespace FSH.Framework.Tenant.Contracts.Dtos; +public sealed class TenantDto { public string Id { get; set; } = default!; public string Name { get; set; } = default!; @@ -8,4 +8,4 @@ public class TenantDetail public bool IsActive { get; set; } public DateTime ValidUpto { get; set; } public string? Issuer { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj b/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj index 90ca89d4c..a5cfd6497 100644 --- a/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj +++ b/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj @@ -8,5 +8,8 @@ enable enable + + + diff --git a/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs b/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs new file mode 100644 index 000000000..27262e2d7 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Tenant.Contracts.v1.ActivateTenant; +public sealed record ActivateTenantCommand(string TenantId) : ICommand; diff --git a/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs b/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs new file mode 100644 index 000000000..eb618c5ef --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Tenant.Contracts.v1.ActivateTenant; +public sealed record ActivateTenantCommandResponse(string TenantId, string Status); \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs b/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs new file mode 100644 index 000000000..f531c81b0 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs @@ -0,0 +1,9 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Tenant.Contracts.v1.CreateTenant; +public sealed record CreateTenantCommand( + string Id, + string Name, + string? ConnectionString, + string AdminEmail, + string? Issuer) : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs b/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs new file mode 100644 index 000000000..251ffe698 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Tenant.Contracts.v1.CreateTenant; +public sealed record CreateTenantCommandResponse(string Id); \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs b/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs new file mode 100644 index 000000000..0adbcfe0e --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Tenant.Contracts.v1.DisableTenant; +public sealed record DisableTenantCommand(string TenantId) : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs b/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs new file mode 100644 index 000000000..0546390b3 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Tenant.Contracts.v1.DisableTenant; +public sealed record DisableTenantCommandResponse(string Status); \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs b/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs new file mode 100644 index 000000000..b50159844 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Tenant.Contracts.v1.GetTenantById; +public sealed record GetTenantByIdQuery(string TenantId) : IQuery; \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs b/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs new file mode 100644 index 000000000..daf1cf346 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Tenant.Contracts.Dtos; + +namespace FSH.Framework.Tenant.Contracts.v1.GetTenantById; +public sealed record GetTenantByIdQueryResponse(TenantDto Tenant); \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs b/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs new file mode 100644 index 000000000..0d81ff447 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Tenant.Contracts.v1.GetTenants; +public sealed record GetTenantsQuery : IQuery; \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs b/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs new file mode 100644 index 000000000..bd8363035 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs @@ -0,0 +1,4 @@ +using FSH.Framework.Tenant.Contracts.Dtos; + +namespace FSH.Framework.Tenant.Contracts.v1.GetTenants; +public sealed record GetTenantsQueryResponse(IReadOnlyCollection Tenants); \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs b/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs new file mode 100644 index 000000000..0b76c5d20 --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs @@ -0,0 +1,5 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; +public sealed record UpgradeTenantCommand(string Tenant, DateTime ExtendedExpiryDate) + : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs b/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs new file mode 100644 index 000000000..7293d4dfc --- /dev/null +++ b/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; +public sealed record UpgradeTenantCommandResponse(DateTime NewValidity, string Tenant); \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant.cs b/src/framework/Modules/Tenant/Features/v1/ActivateTenant.cs deleted file mode 100644 index d185f2199..000000000 --- a/src/framework/Modules/Tenant/Features/v1/ActivateTenant.cs +++ /dev/null @@ -1,37 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Services; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Features.v1; -public static class ActivateTenant -{ - public sealed record Command(string TenantId) : ICommand; - public record Response(string Status); - public sealed class Validator : AbstractValidator - { - public Validator() => - RuleFor(t => t.TenantId) - .NotEmpty(); - } - public sealed class Handler(ITenantService tenantService) : ICommandHandler - { - public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) - { - var result = await tenantService.ActivateAsync(command.TenantId, cancellationToken); - return new Response(result); - } - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/{id}/activate", async (ICommandDispatcher dispatcher, string id) - => await dispatcher.SendAsync(new Command(id))) - .WithName(nameof(ActivateTenant)) - .WithSummary("activate tenant") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("activate tenant"); - } -} diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs new file mode 100644 index 000000000..4aad68506 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs @@ -0,0 +1,16 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.v1.ActivateTenant; +using FSH.Framework.Tenant.Services; + +namespace FSH.Framework.Tenant.Features.v1.ActivateTenant; +public sealed class ActivateTenantCommandHandler(ITenantService tenantService) + : ICommandHandler +{ + public async Task HandleAsync( + ActivateTenantCommand command, + CancellationToken cancellationToken = default) + { + var result = await tenantService.ActivateAsync(command.TenantId, cancellationToken); + return new ActivateTenantCommandResponse(result, command.TenantId); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs new file mode 100644 index 000000000..bf3adbdd9 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs @@ -0,0 +1,10 @@ +using FluentValidation; +using FSH.Framework.Tenant.Contracts.v1.ActivateTenant; + +namespace FSH.Framework.Tenant.Features.v1.ActivateTenant; +public sealed class ActivateTenantCommandValidator : AbstractValidator +{ + public ActivateTenantCommandValidator() => + RuleFor(t => t.TenantId) + .NotEmpty(); +} diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs new file mode 100644 index 000000000..a72a8e16d --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Contracts.v1.ActivateTenant; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Features.v1.ActivateTenant; +public static class ActivateTenantEndpoint +{ + public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/{id}/activate", async (ICommandDispatcher dispatcher, string id) + => await dispatcher.SendAsync(new ActivateTenantCommand(id))) + .WithName(nameof(ActivateTenantEndpoint)) + .WithSummary("activate tenant") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("activate tenant"); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant.cs deleted file mode 100644 index 14e56a9ca..000000000 --- a/src/framework/Modules/Tenant/Features/v1/CreateTenant.cs +++ /dev/null @@ -1,61 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Core.Persistence; -using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Services; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Features.v1; -public static class CreateTenant -{ - public sealed record Command(string Id, string Name, string? ConnectionString, string AdminEmail, string? Issuer) : ICommand; - public sealed record Response(string Id); - public class Validator : AbstractValidator - { - public Validator(ITenantService tenantService, IConnectionStringValidator connectionStringValidator) - { - RuleFor(t => t.Id).Cascade(CascadeMode.Stop) - .NotEmpty() - .MustAsync(async (id, _) => !await tenantService.ExistsWithIdAsync(id).ConfigureAwait(false)) - .WithMessage((_, id) => $"Tenant {id} already exists."); - - RuleFor(t => t.Name).Cascade(CascadeMode.Stop) - .NotEmpty() - .MustAsync(async (name, _) => !await tenantService.ExistsWithNameAsync(name!).ConfigureAwait(false)) - .WithMessage((_, name) => $"Tenant {name} already exists."); - - RuleFor(t => t.ConnectionString).Cascade(CascadeMode.Stop) - .Must((_, cs) => string.IsNullOrWhiteSpace(cs) || connectionStringValidator.TryValidate(cs)) - .WithMessage("Connection string invalid."); - - RuleFor(t => t.AdminEmail).Cascade(CascadeMode.Stop) - .NotEmpty() - .EmailAddress(); - } - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/", async (ICommandDispatcher dispatcher, Command command) - => await dispatcher.SendAsync(command)) - .WithName(nameof(ActivateTenant)) - .WithSummary("activate tenant") - .RequirePermission("Permissions.Tenants.Create") - .WithDescription("activate tenant"); - } - public sealed class Handler(ITenantService service) : ICommandHandler - { - public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) - { - var tenantId = await service.CreateAsync(command.Id, - command.Name, - command.ConnectionString, - command.AdminEmail, - command.Issuer, - cancellationToken); - return new Response(tenantId); - } - } - -} diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs new file mode 100644 index 000000000..1b5dc1717 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs @@ -0,0 +1,21 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.v1.CreateTenant; +using FSH.Framework.Tenant.Services; + +namespace FSH.Framework.Tenant.Features.v1.CreateTenant; +internal class CreateTenantCommandHandler(ITenantService service) + : ICommandHandler +{ + public async Task HandleAsync( + CreateTenantCommand command, + CancellationToken cancellationToken = default) + { + var tenantId = await service.CreateAsync(command.Id, + command.Name, + command.ConnectionString, + command.AdminEmail, + command.Issuer, + cancellationToken); + return new CreateTenantCommandResponse(tenantId); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs new file mode 100644 index 000000000..861b5c36d --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs @@ -0,0 +1,29 @@ +using FluentValidation; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Tenant.Contracts.v1.CreateTenant; +using FSH.Framework.Tenant.Services; + +namespace FSH.Framework.Tenant.Features.v1.CreateTenant; +public class CreateTenantCommandValidator : AbstractValidator +{ + public CreateTenantCommandValidator(ITenantService tenantService, IConnectionStringValidator connectionStringValidator) + { + RuleFor(t => t.Id).Cascade(CascadeMode.Stop) + .NotEmpty() + .MustAsync(async (id, _) => !await tenantService.ExistsWithIdAsync(id).ConfigureAwait(false)) + .WithMessage((_, id) => $"Tenant {id} already exists."); + + RuleFor(t => t.Name).Cascade(CascadeMode.Stop) + .NotEmpty() + .MustAsync(async (name, _) => !await tenantService.ExistsWithNameAsync(name!).ConfigureAwait(false)) + .WithMessage((_, name) => $"Tenant {name} already exists."); + + RuleFor(t => t.ConnectionString).Cascade(CascadeMode.Stop) + .Must((_, cs) => string.IsNullOrWhiteSpace(cs) || connectionStringValidator.TryValidate(cs)) + .WithMessage("Connection string invalid."); + + RuleFor(t => t.AdminEmail).Cascade(CascadeMode.Stop) + .NotEmpty() + .EmailAddress(); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs new file mode 100644 index 000000000..781a1a2b7 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Contracts.v1.CreateTenant; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Features.v1.CreateTenant; +public static class CreateTenantEndpoint +{ + internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/", async (ICommandDispatcher dispatcher, CreateTenantCommand command) + => await dispatcher.SendAsync(command)) + .WithName(nameof(CreateTenantEndpoint)) + .WithSummary("activate tenant") + .RequirePermission("Permissions.Tenants.Create") + .WithDescription("activate tenant"); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/DisableTenant.cs b/src/framework/Modules/Tenant/Features/v1/DisableTenant.cs deleted file mode 100644 index 9ce3e5e4d..000000000 --- a/src/framework/Modules/Tenant/Features/v1/DisableTenant.cs +++ /dev/null @@ -1,38 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Services; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Features.v1; -public static class DisableTenant -{ - public sealed record Command(string TenantId) : ICommand; - public sealed record Response(string Status); - public sealed class DisableTenantValidator : AbstractValidator - { - public DisableTenantValidator() => - RuleFor(t => t.TenantId) - .NotEmpty(); - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/{id}/deactivate", (ICommandDispatcher dispatcher, string id) - => dispatcher.SendAsync(new Command(id))) - .WithName(nameof(DisableTenant)) - .WithSummary("activate tenant") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("activate tenant"); - } - public sealed class Handler(ITenantService service) : ICommandHandler - { - public async Task HandleAsync(Command request, CancellationToken cancellationToken = default) - { - var status = await service.DeactivateAsync(request.TenantId); - return new Response(status); - } - } - -} diff --git a/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs b/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs new file mode 100644 index 000000000..08f475cc6 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs @@ -0,0 +1,16 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.v1.DisableTenant; +using FSH.Framework.Tenant.Services; + +namespace FSH.Framework.Tenant.Features.v1.DisableTenant; +public class DisableTenantCommandHandler(ITenantService service) + : ICommandHandler +{ + public async Task HandleAsync( + DisableTenantCommand request, + CancellationToken cancellationToken = default) + { + var status = await service.DeactivateAsync(request.TenantId); + return new DisableTenantCommandResponse(status); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs b/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs new file mode 100644 index 000000000..77754be04 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs @@ -0,0 +1,10 @@ +using FluentValidation; +using FSH.Framework.Tenant.Contracts.v1.DisableTenant; + +namespace FSH.Framework.Tenant.Features.v1.DisableTenant; +internal class DisableTenantCommandValidator : AbstractValidator +{ + public DisableTenantCommandValidator() => + RuleFor(t => t.TenantId) + .NotEmpty(); +} diff --git a/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs new file mode 100644 index 000000000..5726922b5 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Contracts.v1.DisableTenant; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Features.v1.DisableTenant; +public static class DisableTenantEndpoint +{ + internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/{id}/deactivate", (ICommandDispatcher dispatcher, string id) + => dispatcher.SendAsync(new DisableTenantCommand(id))) + .WithName(nameof(DisableTenantEndpoint)) + .WithSummary("activate tenant") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("activate tenant"); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenantById.cs b/src/framework/Modules/Tenant/Features/v1/GetTenantById.cs deleted file mode 100644 index bfe48d3c9..000000000 --- a/src/framework/Modules/Tenant/Features/v1/GetTenantById.cs +++ /dev/null @@ -1,51 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Services; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Features.v1; -public static class GetTenantById -{ - public sealed record Query(string TenantId) : IQuery; - public class Response - { - public string Id { get; set; } = default!; - public string Name { get; set; } = default!; - public string? ConnectionString { get; set; } - public string AdminEmail { get; set; } = default!; - public bool IsActive { get; set; } - public DateTime ValidUpto { get; set; } - public string? Issuer { get; set; } - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/{id}", (IQueryDispatcher dispatcher, string id) - => dispatcher.SendAsync(new Query(id))) - .WithName(nameof(GetTenantById)) - .WithSummary("get tenant by id") - .RequirePermission("Permissions.Tenants.View") - .WithDescription("get tenant by id"); - } - public sealed class Handler(ITenantService service, IQueryDispatcher dispatcher) : IQueryHandler - { - public async Task HandleAsync(Query query, CancellationToken cancellationToken = default) - { - - var data = await dispatcher.SendAsync(new Query(query.TenantId), cancellationToken); - var tenant = await service.GetByIdAsync(query.TenantId); - return new Response() - { - Id = tenant.Id, - Name = tenant.Name, - ConnectionString = tenant.ConnectionString, - AdminEmail = tenant.AdminEmail, - IsActive = tenant.IsActive, - ValidUpto = tenant.ValidUpto, - Issuer = tenant.Issuer, - }; - } - } - -} diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs new file mode 100644 index 000000000..f4899a692 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Contracts.v1.GetTenantById; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Features.v1.GetTenantById; +public static class GetTenantByIdEndpoint +{ + internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/{id}", (IQueryDispatcher dispatcher, string id) + => dispatcher.SendAsync(new GetTenantByIdQuery(id))) + .WithName(nameof(GetTenantByIdEndpoint)) + .WithSummary("get tenant by id") + .RequirePermission("Permissions.Tenants.View") + .WithDescription("get tenant by id"); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs b/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs new file mode 100644 index 000000000..0eb5fa16c --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs @@ -0,0 +1,17 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.Dtos; +using FSH.Framework.Tenant.Contracts.v1.GetTenantById; +using FSH.Framework.Tenant.Services; +using Mapster; + +namespace FSH.Framework.Tenant.Features.v1.GetTenantById; +internal class GetTenantByIdQueryHandler(ITenantService service) + : IQueryHandler +{ + public async Task HandleAsync(GetTenantByIdQuery query, CancellationToken cancellationToken = default) + { + var tenant = await service.GetByIdAsync(query.TenantId); + var tenantDto = tenant.Adapt(); + return new GetTenantByIdQueryResponse(tenantDto); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenants.cs b/src/framework/Modules/Tenant/Features/v1/GetTenants.cs deleted file mode 100644 index f5afcb536..000000000 --- a/src/framework/Modules/Tenant/Features/v1/GetTenants.cs +++ /dev/null @@ -1,37 +0,0 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Services; -using Mapster; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Features.v1; -public static class GetTenants -{ - public sealed class Query : IQuery; - public sealed class Response - { - public IReadOnlyCollection Tenants { get; init; } = []; - } - public static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapGet("/", (IQueryDispatcher dispatcher) => dispatcher.SendAsync(new Query())) - .WithName(nameof(GetTenants)) - .WithSummary("get tenants") - .RequirePermission("Permissions.Tenants.View") - .WithDescription("get tenants"); - } - public sealed class GetTenantsHandler(ITenantService service) : IQueryHandler - { - public async Task HandleAsync(Query request, CancellationToken cancellationToken = default) - { - var tenants = await service.GetAllAsync(); - return new Response - { - Tenants = tenants.Adapt>() - }; - } - } - -} diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs new file mode 100644 index 000000000..8268ac792 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Contracts.v1.GetTenants; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Features.v1.GetTenants; +public static class GetTenantsEndpoint +{ + public static RouteHandlerBuilder Map(IEndpointRouteBuilder endpoints) + { + return endpoints.MapGet("/", (IQueryDispatcher dispatcher) + => dispatcher.SendAsync(new GetTenantsQuery())) + .WithName(nameof(GetTenantsEndpoint)) + .WithSummary("get tenants") + .RequirePermission("Permissions.Tenants.View") + .WithDescription("get tenants"); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs b/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs new file mode 100644 index 000000000..7b89ec35f --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs @@ -0,0 +1,17 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.Dtos; +using FSH.Framework.Tenant.Contracts.v1.GetTenants; +using FSH.Framework.Tenant.Services; +using Mapster; + +namespace FSH.Framework.Tenant.Features.v1.GetTenants; + +public sealed class GetTenantsQueryHandler(ITenantService service) + : IQueryHandler +{ + public async Task HandleAsync(GetTenantsQuery query, CancellationToken cancellationToken = default) + { + var tenants = await service.GetAllAsync(); + return new GetTenantsQueryResponse(tenants.Adapt>()); + } +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeSubscription.cs b/src/framework/Modules/Tenant/Features/v1/UpgradeSubscription.cs deleted file mode 100644 index 7aa3be740..000000000 --- a/src/framework/Modules/Tenant/Features/v1/UpgradeSubscription.cs +++ /dev/null @@ -1,41 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Shared.Authorization; -using FSH.Framework.Tenant.Services; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Tenant.Features.v1; - -public static class UpgradeSubscription -{ - public record Command(string Tenant, DateTime ExtendedExpiryDate) : ICommand; - public record Response(DateTime NewValidity, string Tenant); - public class Validator : AbstractValidator - { - public Validator() - { - RuleFor(t => t.Tenant).NotEmpty(); - RuleFor(t => t.ExtendedExpiryDate).GreaterThan(DateTime.UtcNow); - } - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/upgrade", (Command command, ICommandDispatcher dispatcher) - => dispatcher.SendAsync(command)) - .WithName(nameof(UpgradeSubscription)) - .WithSummary("upgrade tenant subscription") - .RequirePermission("Permissions.Tenants.Update") - .WithDescription("upgrade tenant subscription"); - } - public class Handler(ITenantService service) : ICommandHandler - { - public async Task HandleAsync(Command request, CancellationToken cancellationToken = default) - { - var validUpto = await service.UpgradeSubscription(request.Tenant, request.ExtendedExpiryDate); - return new Response(validUpto, request.Tenant); - } - } - -} diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs new file mode 100644 index 000000000..c005b0997 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs @@ -0,0 +1,16 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; +using FSH.Framework.Tenant.Services; + +namespace FSH.Framework.Tenant.Features.v1.UpgradeTenant; +internal class UpgradeTenantCommandHandler(ITenantService service) + : ICommandHandler +{ + public async Task HandleAsync( + UpgradeTenantCommand request, + CancellationToken cancellationToken = default) + { + var validUpto = await service.UpgradeSubscription(request.Tenant, request.ExtendedExpiryDate); + return new UpgradeTenantCommandResponse(validUpto, request.Tenant); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs new file mode 100644 index 000000000..032ac5f30 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs @@ -0,0 +1,12 @@ +using FluentValidation; +using FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; + +namespace FSH.Framework.Tenant.Features.v1.UpgradeTenant; +public sealed class UpgradeTenantCommandValidator : AbstractValidator +{ + public UpgradeTenantCommandValidator() + { + RuleFor(t => t.Tenant).NotEmpty(); + RuleFor(t => t.ExtendedExpiryDate).GreaterThan(DateTime.UtcNow); + } +} diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs new file mode 100644 index 000000000..627d58d71 --- /dev/null +++ b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs @@ -0,0 +1,20 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Tenant.Features.v1.UpgradeTenant; +public static class UpgradeTenantEndpoint +{ + internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/upgrade", (UpgradeTenantCommand command, ICommandDispatcher dispatcher) + => dispatcher.SendAsync(command)) + .WithName(nameof(UpgradeTenantEndpoint)) + .WithSummary("upgrade tenant subscription") + .RequirePermission("Permissions.Tenants.Update") + .WithDescription("upgrade tenant subscription"); + } +} diff --git a/src/framework/Modules/Tenant/Services/ITenantService.cs b/src/framework/Modules/Tenant/Services/ITenantService.cs index a23c58cd7..86987fc8d 100644 --- a/src/framework/Modules/Tenant/Services/ITenantService.cs +++ b/src/framework/Modules/Tenant/Services/ITenantService.cs @@ -1,14 +1,16 @@ -namespace FSH.Framework.Tenant.Services; +using FSH.Framework.Tenant.Contracts.Dtos; + +namespace FSH.Framework.Tenant.Services; public interface ITenantService { - Task> GetAllAsync(); + Task> GetAllAsync(); Task ExistsWithIdAsync(string id); Task ExistsWithNameAsync(string name); - Task GetByIdAsync(string id); + Task GetByIdAsync(string id); Task CreateAsync(string id, string name, string? connectionString, string adminEmail, string? issuer, CancellationToken cancellationToken); diff --git a/src/framework/Modules/Tenant/Services/TenantService.cs b/src/framework/Modules/Tenant/Services/TenantService.cs index 42b5362fc..953217f6e 100644 --- a/src/framework/Modules/Tenant/Services/TenantService.cs +++ b/src/framework/Modules/Tenant/Services/TenantService.cs @@ -3,6 +3,7 @@ using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Persistence; using FSH.Framework.Shared.Multitenancy; +using FSH.Framework.Tenant.Contracts.Dtos; using Mapster; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -96,15 +97,15 @@ public async Task ExistsWithIdAsync(string id) => public async Task ExistsWithNameAsync(string name) => (await _tenantStore.GetAllAsync().ConfigureAwait(false)).Any(t => t.Name == name); - public async Task> GetAllAsync() + public async Task> GetAllAsync() { - var tenants = (await _tenantStore.GetAllAsync().ConfigureAwait(false)).Adapt>(); + var tenants = (await _tenantStore.GetAllAsync().ConfigureAwait(false)).Adapt>(); return tenants; } - public async Task GetByIdAsync(string id) => + public async Task GetByIdAsync(string id) => (await GetTenantInfoAsync(id).ConfigureAwait(false)) - .Adapt(); + .Adapt(); public async Task UpgradeSubscription(string id, DateTime extendedExpiryDate) { diff --git a/src/framework/Modules/Tenant/Tenant.csproj b/src/framework/Modules/Tenant/Tenant.csproj index 689a1bc2d..3c5e1dd17 100644 --- a/src/framework/Modules/Tenant/Tenant.csproj +++ b/src/framework/Modules/Tenant/Tenant.csproj @@ -11,6 +11,10 @@ + + + + diff --git a/src/framework/Modules/Tenant/TenantModule.cs b/src/framework/Modules/Tenant/TenantModule.cs index ec56c898f..99d9f9941 100644 --- a/src/framework/Modules/Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/TenantModule.cs @@ -1,7 +1,12 @@ using Asp.Versioning; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Modules; -using FSH.Framework.Tenant.Features.v1; +using FSH.Framework.Tenant.Features.v1.ActivateTenant; +using FSH.Framework.Tenant.Features.v1.CreateTenant; +using FSH.Framework.Tenant.Features.v1.DisableTenant; +using FSH.Framework.Tenant.Features.v1.GetTenantById; +using FSH.Framework.Tenant.Features.v1.GetTenants; +using FSH.Framework.Tenant.Features.v1.UpgradeTenant; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -33,12 +38,12 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) .WithOpenApi() .WithApiVersionSet(apiVersionSet); - ActivateTenant.MapEndpoint(group); - CreateTenant.MapEndpoint(group); - DisableTenant.MapEndpoint(group); - GetTenantById.MapEndpoint(group); - GetTenants.MapEndpoint(group); - UpgradeSubscription.MapEndpoint(group); + CreateTenantEndpoint.Map(group); + DisableTenantEndpoint.Map(group); + GetTenantByIdEndpoint.Map(group); + GetTenantsEndpoint.Map(group); + UpgradeTenantEndpoint.Map(group); + ActivateTenantEndpoint.Map(group); return endpoints; } From 49e2bc5e981553c94739cd4bc8495042fc516a3d Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Sat, 12 Apr 2025 19:09:49 +0530 Subject: [PATCH 26/54] almost there --- .../Core/Messaging/Events/IEventPublisher.cs | 4 +- .../SpecificationBuilderExtensions.cs | 10 +- src/framework/FSH.Framework.sln | 35 ++-- .../Dtos}/RoleDto.cs | 0 .../Dtos}/TokenDto.cs | 0 .../Dtos/UserDto.cs} | 2 +- .../Dtos/UserRoleDto.cs} | 2 +- .../Identity.Contracts.csproj | 15 ++ .../IdentityModuleConstants.cs | 6 + .../UpdatePermissionsCommand.cs | 2 +- .../UpdatePermissionsCommandValidator.cs} | 4 +- .../v1/Roles/UpsertRole/UpsertRoleCommand.cs} | 2 +- .../UpsertRole/UpsertRoleCommandValidator.cs} | 4 +- .../RefreshToken/RefreshTokenCommand.cs | 6 + .../RefreshTokenCommandResponse.cs | 5 + .../TokenGeneration/TokenGenerationCommand.cs | 5 + .../TokenGenerationCommandResponse.cs | 5 + .../AssignUserRoles/AssignUserRolesCommand.cs | 9 + .../AssignUserRolesCommandResponse.cs | 2 + .../ChangePassword/ChangePasswordCommand.cs | 6 +- .../ForgotPassword/ForgotPasswordCommand.cs | 0 .../Users/RegisterUser/RegisterUserCommand.cs | 6 +- .../RegisterUser/RegisterUserResponse.cs | 0 .../ResetPassword/ResetPasswordCommand.cs | 0 .../ToggleUserStatusCommand.cs | 0 .../v1/Users/UpdateUser/UpdateUserCommand.cs | 2 +- .../PermissionAuthorizationRequirement.cs | 0 ...quiredPermissionAuthorizationExtensions.cs | 0 .../RequiredPermissionAuthorizationHandler.cs | 0 .../Data/IdentityConfigurations.cs | 0 .../Data/IdentityDbContext.cs | 2 + .../Data/IdentityDbInitializer.cs | 0 src/framework/Identity/Identity.csproj | 17 ++ src/framework/Identity/IdentityModule.cs | 53 +++++ .../Options}/JwtOptions.cs | 2 + .../Services}/CurrentUserService.cs | 0 .../Services}/ICurrentUserInitializer.cs | 0 .../Identity/Services/IRoleService.cs | 16 ++ .../Identity/Services/ITokenService.cs | 6 + .../Identity/Services/IUserService.cs | 33 +++ .../Services}/TokenService.cs | 73 ++++--- .../Services}/UserService.Password.cs | 0 .../Services}/UserService.Permissions.cs | 0 .../Services}/UserService.cs | 6 +- .../v1}/RoleClaims/FshRoleClaim.cs | 2 +- .../v1}/Roles/FshRole.cs | 0 .../v1}/Roles/RoleService.cs | 29 +-- .../RefreshTokenCommandHandler.cs | 19 ++ .../RefreshTokenCommandValidator.cs | 12 ++ .../RefreshToken/RefreshTokenEndpoint.cs | 26 +++ .../TokenGenerationCommandHandler.cs | 17 ++ .../TokenGenerationCommandValidator.cs | 18 ++ .../TokenGenerationEndpoint.cs | 27 +++ .../AssignUserRolesCommandHandler.cs | 13 ++ .../AssignUserRolesEndpoint.cs | 25 +++ .../ChangePassword}/ChangePasswordEndpoint.cs | 6 +- .../ChangePassword/ChangePasswordValidator.cs | 0 .../ConfirmEmail}/ConfirmEmailEndpoint.cs | 0 .../Users/DeleteUser}/DeleteUserEndpoint.cs | 0 .../ForgotPasswordCommandValidator.cs} | 4 +- .../ForgotPassword}/ForgotPasswordEndpoint.cs | 0 .../v1}/Users/FshUser.cs | 0 .../v1/Users/GetUser}/GetUserEndpoint.cs | 0 .../GetUserPermissionsEndpoint.cs | 0 .../GetUserProfile}/GetUserProfileEndpoint.cs | 0 .../GetUserRoles}/GetUserRolesEndpoint.cs | 4 +- .../Users/GetUsers}/GetUsersListEndpoint.cs | 0 .../RegisterUser}/RegisterUserEndpoint.cs | 0 .../ResetPasswordCommandValidator.cs} | 4 +- .../ResetPassword}/ResetPasswordEndpoint.cs | 0 .../SelfRegisterUserEndpoint.cs | 0 .../ToggleUserStatusEndpoint.cs | 0 .../UpdateUser/UpdateUserCommandValidator.cs | 3 +- .../Users/UpdateUser}/UpdateUserEndpoint.cs | 0 src/framework/Infrastructure/Extensions.cs | 32 +-- .../Infrastructure/Identity/Extensions.cs | 67 ------- .../Infrastructure/Identity/Roles/FshRole.cs | 14 -- .../Identity/Tokens/Endpoints/Extensions.cs | 28 --- .../Identity/Tokens/TokenService.cs | 188 ------------------ .../Identity/Users/Endpoints/Extensions.cs | 27 --- .../Infrastructure/Infrastructure.csproj | 1 + .../Events/InMemoryEventPublisher.cs | 10 +- .../Infrastructure/Modules/Extensions.cs | 42 ++++ .../Modules/IFrameworkModule.cs | 4 + .../Infrastructure/Persistence/Extensions.cs | 2 +- .../Persistence/FshDbContext.cs | 1 + .../Storage/StorageServiceRegistration.cs | 3 +- .../Infrastructure/Tenant/Extensions.cs | 133 ------------- .../Auditing.Contracts/Dtos/TrailDto.cs | 11 +- .../IntegrationEvents/AuditPublishedEvent.cs | 2 +- .../Modules/Auditing/AuditingModule.cs | 2 +- .../Data/Interceptors/AuditInterceptor.cs | 8 +- .../Roles/CreateOrUpdateRoleRequest.cs | 4 - .../Identity.Core/Roles/IRoleService.cs | 13 -- .../Roles/UpdatePermissionsRequest.cs | 4 - .../Identity.Core/Tokens/ITokenService.cs | 6 - .../Tokens/TokenGenerationRequest.cs | 2 - .../Tokens/TokenRefreshRequest.cs | 2 - .../Identity.Core/Users/IUserService.cs | 32 --- .../v1/Tokens/RefreshToken.cs | 48 ----- .../v1/Tokens/TokenGeneration.cs | 56 ------ .../v1/Users/AssignUserRoles.cs | 36 ---- .../IdentityConstants.cs | 5 - src/framework/Modules/Tenant/TenantModule.cs | 133 ++++++++++++- 104 files changed, 645 insertions(+), 820 deletions(-) rename src/framework/{Modules/Identity/Identity.Core/Roles => Identity.Contracts/Dtos}/RoleDto.cs (100%) rename src/framework/{Modules/Identity/Identity.Core/Tokens => Identity.Contracts/Dtos}/TokenDto.cs (100%) rename src/framework/{Modules/Identity/Identity.Core/Users/UserDetailDto.cs => Identity.Contracts/Dtos/UserDto.cs} (94%) rename src/framework/{Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs => Identity.Contracts/Dtos/UserRoleDto.cs} (87%) create mode 100644 src/framework/Identity.Contracts/Identity.Contracts.csproj create mode 100644 src/framework/Identity.Contracts/IdentityModuleConstants.cs rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs (79%) rename src/framework/{Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs => Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommandValidator.cs} (62%) rename src/framework/{Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs => Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs} (85%) rename src/framework/{Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs => Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs} (60%) create mode 100644 src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs create mode 100644 src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs create mode 100644 src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs create mode 100644 src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs create mode 100644 src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs create mode 100644 src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Users/ChangePassword/ChangePasswordCommand.cs (68%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Users/ForgotPassword/ForgotPasswordCommand.cs (100%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Users/RegisterUser/RegisterUserCommand.cs (77%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Users/RegisterUser/RegisterUserResponse.cs (100%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Users/ResetPassword/ResetPasswordCommand.cs (100%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs (100%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity.Contracts}/v1/Users/UpdateUser/UpdateUserCommand.cs (85%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity}/Authorization/PermissionAuthorizationRequirement.cs (100%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity}/Authorization/RequiredPermissionAuthorizationExtensions.cs (100%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity}/Authorization/RequiredPermissionAuthorizationHandler.cs (100%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity}/Data/IdentityConfigurations.cs (100%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity}/Data/IdentityDbContext.cs (94%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity}/Data/IdentityDbInitializer.cs (100%) create mode 100644 src/framework/Identity/Identity.csproj create mode 100644 src/framework/Identity/IdentityModule.cs rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity/Options}/JwtOptions.cs (83%) rename src/framework/{Modules/Identity/Identity.Infrastructure/Users => Identity/Services}/CurrentUserService.cs (100%) rename src/framework/{Modules/Identity/Identity.Core/Users => Identity/Services}/ICurrentUserInitializer.cs (100%) create mode 100644 src/framework/Identity/Services/IRoleService.cs create mode 100644 src/framework/Identity/Services/ITokenService.cs create mode 100644 src/framework/Identity/Services/IUserService.cs rename src/framework/{Modules/Identity/Identity.Infrastructure/Tokens => Identity/Services}/TokenService.cs (76%) rename src/framework/{Modules/Identity/Identity.Infrastructure/Users => Identity/Services}/UserService.Password.cs (100%) rename src/framework/{Modules/Identity/Identity.Infrastructure/Users => Identity/Services}/UserService.Permissions.cs (100%) rename src/framework/{Modules/Identity/Identity.Infrastructure/Users => Identity/Services}/UserService.cs (98%) rename src/framework/{Infrastructure/Identity => Identity/v1}/RoleClaims/FshRoleClaim.cs (76%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity/v1}/Roles/FshRole.cs (100%) rename src/framework/{Infrastructure/Identity => Identity/v1}/Roles/RoleService.cs (81%) create mode 100644 src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs create mode 100644 src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs create mode 100644 src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs create mode 100644 src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs create mode 100644 src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs create mode 100644 src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs create mode 100644 src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs create mode 100644 src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/ChangePassword}/ChangePasswordEndpoint.cs (90%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity}/v1/Users/ChangePassword/ChangePasswordValidator.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/ConfirmEmail}/ConfirmEmailEndpoint.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/DeleteUser}/DeleteUserEndpoint.cs (100%) rename src/framework/{Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs => Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs} (62%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/ForgotPassword}/ForgotPasswordEndpoint.cs (100%) rename src/framework/{Modules/Identity/Identity.Infrastructure => Identity/v1}/Users/FshUser.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/GetUser}/GetUserEndpoint.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/GetUserPermissions}/GetUserPermissionsEndpoint.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/GetUserProfile}/GetUserProfileEndpoint.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/GetUserRoles}/GetUserRolesEndpoint.cs (86%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/GetUsers}/GetUsersListEndpoint.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/RegisterUser}/RegisterUserEndpoint.cs (100%) rename src/framework/{Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs => Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs} (66%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/ResetPassword}/ResetPasswordEndpoint.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/SelfRegistration}/SelfRegisterUserEndpoint.cs (100%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/ToggleUserStatus}/ToggleUserStatusEndpoint.cs (100%) rename src/framework/{Modules/Identity/Identity.Endpoints => Identity}/v1/Users/UpdateUser/UpdateUserCommandValidator.cs (91%) rename src/framework/{Infrastructure/Identity/Users/Endpoints => Identity/v1/Users/UpdateUser}/UpdateUserEndpoint.cs (100%) delete mode 100644 src/framework/Infrastructure/Identity/Extensions.cs delete mode 100644 src/framework/Infrastructure/Identity/Roles/FshRole.cs delete mode 100644 src/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs delete mode 100644 src/framework/Infrastructure/Identity/Tokens/TokenService.cs delete mode 100644 src/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs create mode 100644 src/framework/Infrastructure/Modules/Extensions.cs create mode 100644 src/framework/Infrastructure/Modules/IFrameworkModule.cs delete mode 100644 src/framework/Infrastructure/Tenant/Extensions.cs delete mode 100644 src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs delete mode 100644 src/framework/Modules/Identity/Identity.Core/Roles/IRoleService.cs delete mode 100644 src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs delete mode 100644 src/framework/Modules/Identity/Identity.Core/Tokens/ITokenService.cs delete mode 100644 src/framework/Modules/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs delete mode 100644 src/framework/Modules/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs delete mode 100644 src/framework/Modules/Identity/Identity.Core/Users/IUserService.cs delete mode 100644 src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs delete mode 100644 src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs delete mode 100644 src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs delete mode 100644 src/framework/Modules/Identity/Identity.Infrastructure/IdentityConstants.cs diff --git a/src/framework/Core/Messaging/Events/IEventPublisher.cs b/src/framework/Core/Messaging/Events/IEventPublisher.cs index 9cdfea35d..a395995e6 100644 --- a/src/framework/Core/Messaging/Events/IEventPublisher.cs +++ b/src/framework/Core/Messaging/Events/IEventPublisher.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Core.Messaging.Events; -public interface IEventPublisher where TEvent : IEvent +public interface IEventPublisher { - Task PublishAsync(TEvent appEvent, CancellationToken cancellationToken = default); + Task PublishAsync(IEvent appEvent, CancellationToken cancellationToken = default); } diff --git a/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs b/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs index 7be1545d3..a16362f99 100644 --- a/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs +++ b/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs @@ -1,9 +1,9 @@ -using System.Linq.Expressions; -using System.Reflection; -using System.Text.Json; -using Ardalis.Specification; +using Ardalis.Specification; using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Paging; +using System.Linq.Expressions; +using System.Reflection; +using System.Text.Json; namespace FSH.Framework.Core.Specifications; @@ -32,7 +32,7 @@ public static ISpecificationBuilder PaginateBy( if (filter.OrderBy is { Count: > 0 }) { - query = query.OrderBy(filter.OrderBy); + query = query.OrderBy(filter.OrderBy.ToArray()); } return query; diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 018804e29..4b4ec5156 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -24,12 +24,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Packages.props = Directory.Packages.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Core", "Modules\Identity\Identity.Core\Identity.Core.csproj", "{DC442C2B-54EF-9A66-D650-6074EFA7E311}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Endpoints", "Modules\Identity\Identity.Endpoints\Identity.Endpoints.csproj", "{097D652F-5C24-57C7-B542-2C46739B3B30}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Infrastructure", "Modules\Identity\Identity.Infrastructure\Identity.Infrastructure.csproj", "{32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing", "Modules\Auditing\Auditing.csproj", "{BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Contracts", "Modules\Auditing.Contracts\Auditing.Contracts.csproj", "{E39A5A4F-D453-A6A2-CA94-468FD795246C}" @@ -38,6 +32,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant", "Modules\Tenant\Te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Contracts", "Modules\Tenant.Contracts\Tenant.Contracts.csproj", "{5324A0FF-DBB9-440C-80C2-4891EC719155}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity", "Identity\Identity.csproj", "{CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Contracts", "Identity.Contracts\Identity.Contracts.csproj", "{201606BA-48CE-42F0-B31F-596187F40B2F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,18 +54,6 @@ Global {09380C15-F138-4305-A595-F4C7E16B6E78}.Debug|Any CPU.Build.0 = Debug|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.ActiveCfg = Release|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.Build.0 = Release|Any CPU - {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DC442C2B-54EF-9A66-D650-6074EFA7E311}.Release|Any CPU.Build.0 = Release|Any CPU - {097D652F-5C24-57C7-B542-2C46739B3B30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {097D652F-5C24-57C7-B542-2C46739B3B30}.Debug|Any CPU.Build.0 = Debug|Any CPU - {097D652F-5C24-57C7-B542-2C46739B3B30}.Release|Any CPU.ActiveCfg = Release|Any CPU - {097D652F-5C24-57C7-B542-2C46739B3B30}.Release|Any CPU.Build.0 = Release|Any CPU - {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Debug|Any CPU.Build.0 = Debug|Any CPU - {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Release|Any CPU.ActiveCfg = Release|Any CPU - {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69}.Release|Any CPU.Build.0 = Release|Any CPU {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Debug|Any CPU.Build.0 = Debug|Any CPU {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -84,6 +70,14 @@ Global {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.Build.0 = Debug|Any CPU {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.ActiveCfg = Release|Any CPU {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.Build.0 = Release|Any CPU + {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Release|Any CPU.Build.0 = Release|Any CPU + {201606BA-48CE-42F0-B31F-596187F40B2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {201606BA-48CE-42F0-B31F-596187F40B2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {201606BA-48CE-42F0-B31F-596187F40B2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {201606BA-48CE-42F0-B31F-596187F40B2F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -92,13 +86,12 @@ Global {15EA2212-0958-4415-AA37-116F2A47F23F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {24E922E3-8C91-43A1-A110-D8F5276566BA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {E5141F38-2D08-44DA-9A6C-B96890515168} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {DC442C2B-54EF-9A66-D650-6074EFA7E311} = {15EA2212-0958-4415-AA37-116F2A47F23F} - {097D652F-5C24-57C7-B542-2C46739B3B30} = {15EA2212-0958-4415-AA37-116F2A47F23F} - {32A814DC-DB83-4FAF-0ECC-C6F3180B2B69} = {15EA2212-0958-4415-AA37-116F2A47F23F} {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B} = {E5141F38-2D08-44DA-9A6C-B96890515168} {E39A5A4F-D453-A6A2-CA94-468FD795246C} = {E5141F38-2D08-44DA-9A6C-B96890515168} {27806993-447E-9781-647B-06D3F4AC834A} = {24E922E3-8C91-43A1-A110-D8F5276566BA} {5324A0FF-DBB9-440C-80C2-4891EC719155} = {24E922E3-8C91-43A1-A110-D8F5276566BA} + {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {201606BA-48CE-42F0-B31F-596187F40B2F} = {15EA2212-0958-4415-AA37-116F2A47F23F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} diff --git a/src/framework/Modules/Identity/Identity.Core/Roles/RoleDto.cs b/src/framework/Identity.Contracts/Dtos/RoleDto.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Core/Roles/RoleDto.cs rename to src/framework/Identity.Contracts/Dtos/RoleDto.cs diff --git a/src/framework/Modules/Identity/Identity.Core/Tokens/TokenDto.cs b/src/framework/Identity.Contracts/Dtos/TokenDto.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Core/Tokens/TokenDto.cs rename to src/framework/Identity.Contracts/Dtos/TokenDto.cs diff --git a/src/framework/Modules/Identity/Identity.Core/Users/UserDetailDto.cs b/src/framework/Identity.Contracts/Dtos/UserDto.cs similarity index 94% rename from src/framework/Modules/Identity/Identity.Core/Users/UserDetailDto.cs rename to src/framework/Identity.Contracts/Dtos/UserDto.cs index 1044991ed..a16d55926 100644 --- a/src/framework/Modules/Identity/Identity.Core/Users/UserDetailDto.cs +++ b/src/framework/Identity.Contracts/Dtos/UserDto.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Identity.Core.Users; -public class UserDetailDto +public class UserDto { public string? Id { get; set; } diff --git a/src/framework/Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs b/src/framework/Identity.Contracts/Dtos/UserRoleDto.cs similarity index 87% rename from src/framework/Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs rename to src/framework/Identity.Contracts/Dtos/UserRoleDto.cs index 68314fbf8..dbbb636af 100644 --- a/src/framework/Modules/Identity/Identity.Core/Roles/UserRoleDetailDto.cs +++ b/src/framework/Identity.Contracts/Dtos/UserRoleDto.cs @@ -1,5 +1,5 @@ namespace FSH.Framework.Identity.Core.Roles; -public class UserRoleDetailDto +public class UserRoleDto { public string? RoleId { get; set; } public string? RoleName { get; set; } diff --git a/src/framework/Identity.Contracts/Identity.Contracts.csproj b/src/framework/Identity.Contracts/Identity.Contracts.csproj new file mode 100644 index 000000000..650b6a582 --- /dev/null +++ b/src/framework/Identity.Contracts/Identity.Contracts.csproj @@ -0,0 +1,15 @@ + + + FSH.Framework.Identity.Contracts + FSH.Framework.Identity.Contracts + + + net9.0 + enable + enable + + + + + + diff --git a/src/framework/Identity.Contracts/IdentityModuleConstants.cs b/src/framework/Identity.Contracts/IdentityModuleConstants.cs new file mode 100644 index 000000000..526e267ba --- /dev/null +++ b/src/framework/Identity.Contracts/IdentityModuleConstants.cs @@ -0,0 +1,6 @@ +namespace FSH.Framework.Identity.Contracts; +public static class IdentityModuleConstants +{ + public const string SchemaName = "identity"; + public const int PasswordLength = 10; +} diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs similarity index 79% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs rename to src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs index d499f153c..d2aac3b73 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs +++ b/src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs @@ -10,5 +10,5 @@ public class UpdatePermissionsCommand /// /// The list of permissions to assign to the role. /// - public IReadOnlyList Permissions { get; init; } = Array.Empty(); + public List Permissions { get; init; } = default!; } diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs b/src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommandValidator.cs similarity index 62% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs rename to src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommandValidator.cs index 7536d1c29..555d370e7 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/UpdatePermissions/UpdatePermissionsValidator.cs +++ b/src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommandValidator.cs @@ -1,9 +1,9 @@ using FluentValidation; namespace FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; -public class UpdatePermissionsValidator : AbstractValidator +public class UpdatePermissionsCommandValidator : AbstractValidator { - public UpdatePermissionsValidator() + public UpdatePermissionsCommandValidator() { RuleFor(r => r.RoleId) .NotEmpty(); diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs b/src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs similarity index 85% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs rename to src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs index f64001506..16ebb4d8a 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleCommand.cs +++ b/src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs @@ -1,6 +1,6 @@ namespace FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; -public class CreateOrUpdateRoleCommand +public class UpsertRoleCommand { public string Id { get; set; } = default!; public string Name { get; set; } = default!; diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs b/src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs similarity index 60% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs rename to src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs index a36d583ab..0e1419fd2 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Roles/CreateOrUpdateRole/CreateOrUpdateRoleValidator.cs +++ b/src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs @@ -2,9 +2,9 @@ namespace FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; -public class CreateOrUpdateRoleValidator : AbstractValidator +public class UpsertRoleCommandValidator : AbstractValidator { - public CreateOrUpdateRoleValidator() + public UpsertRoleCommandValidator() { RuleFor(x => x.Name).NotEmpty().WithMessage("Role name is required."); } diff --git a/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs b/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs new file mode 100644 index 000000000..beb117be8 --- /dev/null +++ b/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs @@ -0,0 +1,6 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Contracts.v1.Tokens.RefreshToken; + +namespace FSH.Framework.Identity.Core.Tokens; +public record RefreshTokenCommand(string Token, string RefreshToken) + : ICommand; diff --git a/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs b/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs new file mode 100644 index 000000000..a1c961f43 --- /dev/null +++ b/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Identity.Contracts.v1.Tokens.RefreshToken; +public sealed record RefreshTokenCommandResponse( + string Token, + string RefreshToken, + DateTime RefreshTokenExpiryTime); \ No newline at end of file diff --git a/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs b/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs new file mode 100644 index 000000000..6200040a2 --- /dev/null +++ b/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs @@ -0,0 +1,5 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; +public record TokenGenerationCommand(string Email, string Password, string IpAddress) + : ICommand; diff --git a/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs b/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs new file mode 100644 index 000000000..3dccebb7b --- /dev/null +++ b/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs @@ -0,0 +1,5 @@ +namespace FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; +public sealed record TokenGenerationCommandResponse( + string Token, + string RefreshToken, + DateTime RefreshTokenExpiryTime); \ No newline at end of file diff --git a/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs b/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs new file mode 100644 index 000000000..b6e4dbf73 --- /dev/null +++ b/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs @@ -0,0 +1,9 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Core.Roles; + +namespace FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; +public sealed class AssignUserRolesCommand : ICommand +{ + public required string UserId { get; init; } + public IReadOnlyList UserRoles { get; init; } = Array.Empty(); +} diff --git a/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs b/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs new file mode 100644 index 000000000..5489ea1ef --- /dev/null +++ b/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; +public sealed record AssignUserRolesCommandResponse(string Result); \ No newline at end of file diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs b/src/framework/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs similarity index 68% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs rename to src/framework/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs index a6b36be79..c122c85a1 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordCommand.cs +++ b/src/framework/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs @@ -1,6 +1,8 @@ -namespace FSH.Framework.Identity.Endpoints.v1.Users.ChangePassword; +using FSH.Framework.Core.Messaging.CQRS; -public class ChangePasswordCommand +namespace FSH.Framework.Identity.Contracts.v1.Users.ChangePassword; + +public class ChangePasswordCommand : ICommand { /// The user's current password. public string Password { get; init; } = default!; diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs b/src/framework/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordCommand.cs rename to src/framework/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs b/src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs similarity index 77% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs rename to src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs index c18e4c72e..fe10faa1f 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserCommand.cs +++ b/src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs @@ -1,8 +1,8 @@ -using System.Text.Json.Serialization; -using MediatR; +using FSH.Framework.Core.Messaging.CQRS; +using System.Text.Json.Serialization; namespace FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; -public class RegisterUserCommand : IRequest +public class RegisterUserCommand : ICommand { public string FirstName { get; set; } = default!; public string LastName { get; set; } = default!; diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs b/src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/RegisterUser/RegisterUserResponse.cs rename to src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs b/src/framework/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordCommand.cs rename to src/framework/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs b/src/framework/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs rename to src/framework/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs b/src/framework/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs similarity index 85% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs rename to src/framework/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs index 8a118b815..5336e77b4 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommand.cs +++ b/src/framework/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs @@ -1,6 +1,6 @@ using FSH.Framework.Core.Storage; -namespace FSH.Framework.Identity.Endpoints.v1.Users.UpdateUser; +namespace FSH.Framework.Identity.Contracts.v1.Users.UpdateUser; public class UpdateUserCommand { public string Id { get; set; } = default!; diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs b/src/framework/Identity/Authorization/PermissionAuthorizationRequirement.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Authorization/PermissionAuthorizationRequirement.cs rename to src/framework/Identity/Authorization/PermissionAuthorizationRequirement.cs diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationExtensions.cs rename to src/framework/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/framework/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Authorization/RequiredPermissionAuthorizationHandler.cs rename to src/framework/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs b/src/framework/Identity/Data/IdentityConfigurations.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityConfigurations.cs rename to src/framework/Identity/Data/IdentityConfigurations.cs diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs b/src/framework/Identity/Data/IdentityDbContext.cs similarity index 94% rename from src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs rename to src/framework/Identity/Data/IdentityDbContext.cs index c97dc6646..85d2e308c 100644 --- a/src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbContext.cs +++ b/src/framework/Identity/Data/IdentityDbContext.cs @@ -3,6 +3,8 @@ using FSH.Framework.Core.Persistence; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Identity.v1.RoleClaims; +using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs b/src/framework/Identity/Data/IdentityDbInitializer.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Data/IdentityDbInitializer.cs rename to src/framework/Identity/Data/IdentityDbInitializer.cs diff --git a/src/framework/Identity/Identity.csproj b/src/framework/Identity/Identity.csproj new file mode 100644 index 000000000..740e5af9e --- /dev/null +++ b/src/framework/Identity/Identity.csproj @@ -0,0 +1,17 @@ + + + FSH.Framework.Identity + FSH.Framework.Identity + + + net9.0 + enable + enable + + + + + + + + diff --git a/src/framework/Identity/IdentityModule.cs b/src/framework/Identity/IdentityModule.cs new file mode 100644 index 000000000..86f917f8f --- /dev/null +++ b/src/framework/Identity/IdentityModule.cs @@ -0,0 +1,53 @@ +using FSH.Framework.Core.ExecutionContext; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Identity.Contracts; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Infrastructure.Data; +using FSH.Framework.Identity.Infrastructure.Tokens; +using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Identity.v1.Tokens.TokenGeneration; +using FSH.Framework.Infrastructure.Auth; +using FSH.Framework.Infrastructure.Identity.Roles; +using FSH.Framework.Infrastructure.Identity.Users.Services; +using FSH.Framework.Infrastructure.Persistence; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Framework.Identity; +public static class IdentityModule +{ + public static IServiceCollection RegisterIdentityModule(this IServiceCollection services, IConfiguration config) + { + ArgumentNullException.ThrowIfNull(services); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(sp => (ICurrentUserInitializer)sp.GetRequiredService()); + services.AddTransient(); + services.AddTransient(); + services.BindDbContext(); + services.AddScoped(); + services.AddIdentity(options => + { + options.Password.RequiredLength = IdentityModuleConstants.PasswordLength; + options.Password.RequireDigit = false; + options.Password.RequireLowercase = false; + options.Password.RequireNonAlphanumeric = false; + options.Password.RequireUppercase = false; + options.User.RequireUniqueEmail = true; + }) + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); + return services; + } + + public static IEndpointRouteBuilder MapIdentityEndpoints(this IEndpointRouteBuilder endpoints) + { + TokenGenerationEndpoint.Map(endpoints); + return endpoints; + } +} diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/JwtOptions.cs b/src/framework/Identity/Options/JwtOptions.cs similarity index 83% rename from src/framework/Modules/Identity/Identity.Infrastructure/JwtOptions.cs rename to src/framework/Identity/Options/JwtOptions.cs index 84dd1f57d..fe56d9e13 100644 --- a/src/framework/Modules/Identity/Identity.Infrastructure/JwtOptions.cs +++ b/src/framework/Identity/Options/JwtOptions.cs @@ -4,6 +4,8 @@ namespace FSH.Framework.Identity.Infrastructure; public class JwtOptions : IValidatableObject { public string Key { get; set; } = string.Empty; + public string Issuer { get; set; } = string.Empty; + public string Audience { get; set; } = string.Empty; public int TokenExpirationInMinutes { get; set; } = 60; diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Users/CurrentUserService.cs b/src/framework/Identity/Services/CurrentUserService.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Users/CurrentUserService.cs rename to src/framework/Identity/Services/CurrentUserService.cs diff --git a/src/framework/Modules/Identity/Identity.Core/Users/ICurrentUserInitializer.cs b/src/framework/Identity/Services/ICurrentUserInitializer.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Core/Users/ICurrentUserInitializer.cs rename to src/framework/Identity/Services/ICurrentUserInitializer.cs diff --git a/src/framework/Identity/Services/IRoleService.cs b/src/framework/Identity/Services/IRoleService.cs new file mode 100644 index 000000000..e0be11872 --- /dev/null +++ b/src/framework/Identity/Services/IRoleService.cs @@ -0,0 +1,16 @@ +using FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; +using FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; + +namespace FSH.Framework.Identity.Core.Roles; + +public interface IRoleService +{ + Task> GetRolesAsync(); + Task GetRoleAsync(string id); + Task CreateOrUpdateRoleAsync(UpsertRoleCommand request); + Task DeleteRoleAsync(string id); + Task GetWithPermissionsAsync(string id, CancellationToken cancellationToken); + + Task UpdatePermissionsAsync(UpdatePermissionsCommand request); +} + diff --git a/src/framework/Identity/Services/ITokenService.cs b/src/framework/Identity/Services/ITokenService.cs new file mode 100644 index 000000000..de1e7aea4 --- /dev/null +++ b/src/framework/Identity/Services/ITokenService.cs @@ -0,0 +1,6 @@ +namespace FSH.Framework.Identity.Core.Tokens; +public interface ITokenService +{ + Task GenerateTokenAsync(string email, string password, string ipAddress, CancellationToken cancellationToken); + Task RefreshTokenAsync(string token, string refreshToken, string ipAddress, CancellationToken cancellationToken); +} diff --git a/src/framework/Identity/Services/IUserService.cs b/src/framework/Identity/Services/IUserService.cs new file mode 100644 index 000000000..2ec971c1c --- /dev/null +++ b/src/framework/Identity/Services/IUserService.cs @@ -0,0 +1,33 @@ +using FSH.Framework.Core.Storage; +using FSH.Framework.Identity.Core.Roles; +using System.Security.Claims; + +namespace FSH.Framework.Identity.Core.Users; +public interface IUserService +{ + Task ExistsWithNameAsync(string name); + Task ExistsWithEmailAsync(string email, string? exceptId = null); + Task ExistsWithPhoneNumberAsync(string phoneNumber, string? exceptId = null); + Task> GetListAsync(CancellationToken cancellationToken); + Task GetCountAsync(CancellationToken cancellationToken); + Task GetAsync(string userId, CancellationToken cancellationToken); + Task ToggleStatusAsync(bool activateUser, string userId, CancellationToken cancellationToken); + Task GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal); + Task RegisterAsync(string firstName, string lastName, string email, string userName, string password, string confirmPassword, string phoneNumber, string origin, CancellationToken cancellationToken); + Task UpdateAsync(string userId, string firstName, string lastName, string email, FileUploadRequest image, bool deleteCurrentImage); + Task DeleteAsync(string userId); + Task ConfirmEmailAsync(string userId, string code, string tenant, CancellationToken cancellationToken); + Task ConfirmPhoneNumberAsync(string userId, string code); + + // permisions + Task HasPermissionAsync(string userId, string permission, CancellationToken cancellationToken = default); + + // passwords + Task ForgotPasswordAsync(string email, string origin, CancellationToken cancellationToken); + Task ResetPasswordAsync(string email, string password, string token, CancellationToken cancellationToken); + Task?> GetPermissionsAsync(string userId, CancellationToken cancellationToken); + + Task ChangePasswordAsync(string password, string newPassword, string confirmNewPassword, string userId); + Task AssignRolesAsync(string userId, IReadOnlyList userRoles, CancellationToken cancellationToken); + Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken); +} diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Tokens/TokenService.cs b/src/framework/Identity/Services/TokenService.cs similarity index 76% rename from src/framework/Modules/Identity/Identity.Infrastructure/Tokens/TokenService.cs rename to src/framework/Identity/Services/TokenService.cs index edbf8cfd2..a9fc752b2 100644 --- a/src/framework/Modules/Identity/Identity.Infrastructure/Tokens/TokenService.cs +++ b/src/framework/Identity/Services/TokenService.cs @@ -1,20 +1,20 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Security.Cryptography; -using System.Text; -using Finbuckle.MultiTenant.Abstractions; -using FSH.Framework.Auditing.Contracts; +using Finbuckle.MultiTenant.Abstractions; +using FSH.Framework.Auditing.Contracts.Dtos; using FSH.Framework.Auditing.Contracts.Enums; -using FSH.Framework.Auditing.Contracts.Events; +using FSH.Framework.Auditing.Contracts.Events.IntegrationEvents; using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.Messaging.Events; using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Identity.Infrastructure.Users; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; -using MediatR; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; namespace FSH.Framework.Identity.Infrastructure.Tokens; public sealed class TokenService : ITokenService @@ -22,8 +22,12 @@ public sealed class TokenService : ITokenService private readonly UserManager _userManager; private readonly IMultiTenantContextAccessor? _multiTenantContextAccessor; private readonly JwtOptions _jwtOptions; - private readonly IPublisher _publisher; - public TokenService(IOptions jwtOptions, UserManager userManager, IMultiTenantContextAccessor? multiTenantContextAccessor, IPublisher publisher) + private readonly IEventPublisher _publisher; + public TokenService( + IOptions jwtOptions, + UserManager userManager, + IMultiTenantContextAccessor? multiTenantContextAccessor, + IEventPublisher publisher) { _jwtOptions = jwtOptions.Value; _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); @@ -31,13 +35,17 @@ public TokenService(IOptions jwtOptions, UserManager userMa _publisher = publisher; } - public async Task GenerateTokenAsync(TokenGenerationRequest request, string ipAddress, CancellationToken cancellationToken) + public async Task GenerateTokenAsync( + string email, + string password, + string ipAddress, + CancellationToken cancellationToken) { var currentTenant = _multiTenantContextAccessor!.MultiTenantContext.TenantInfo; if (currentTenant == null) throw new UnauthorizedException(); if (string.IsNullOrWhiteSpace(currentTenant.Id) - || await _userManager.FindByEmailAsync(request.Email.Trim().Normalize()) is not { } user - || !await _userManager.CheckPasswordAsync(user, request.Password)) + || await _userManager.FindByEmailAsync(email.Trim().Normalize()) is not { } user + || !await _userManager.CheckPasswordAsync(user, password)) { throw new UnauthorizedException(); } @@ -69,9 +77,13 @@ public async Task GenerateTokenAsync(TokenGenerationRequest request, s } - public async Task RefreshTokenAsync(TokenRefreshRequest request, string ipAddress, CancellationToken cancellationToken) + public async Task RefreshTokenAsync( + string token, + string refreshToken, + string ipAddress, + CancellationToken cancellationToken) { - var userPrincipal = GetPrincipalFromExpiredToken(request.Token); + var userPrincipal = GetPrincipalFromExpiredToken(token); var userId = _userManager.GetUserId(userPrincipal)!; var user = await _userManager.FindByIdAsync(userId); if (user is null) @@ -79,14 +91,16 @@ public async Task RefreshTokenAsync(TokenRefreshRequest request, strin throw new UnauthorizedException(); } - if (user.RefreshToken != request.RefreshToken || user.RefreshTokenExpiryTime <= DateTime.UtcNow) + if (user.RefreshToken != refreshToken || user.RefreshTokenExpiryTime <= DateTime.UtcNow) { throw new UnauthorizedException("Invalid Refresh Token"); } return await GenerateTokensAndUpdateUser(user, ipAddress); } - private async Task GenerateTokensAndUpdateUser(FshUser user, string ipAddress) + private async Task GenerateTokensAndUpdateUser( + FshUser user, + string ipAddress) { string token = GenerateJwt(user, ipAddress); @@ -95,19 +109,16 @@ private async Task GenerateTokensAndUpdateUser(FshUser user, string ip await _userManager.UpdateAsync(user); - await _publisher.Publish(new AuditPublishedEvent(new List + await _publisher.PublishAsync(new AuditPublishedEvent(new List { - new() { - Id = Guid.NewGuid(), - Operation = AuditOperation.Create, - Description = "Token Generated.", - EntityName = "Identity", - UserId = new Guid(user.Id), - DateTime = DateTime.UtcNow, - } + new(Guid.NewGuid(), + DateTime.UtcNow, + new Guid(user.Id), + AuditOperation.Create, + "Token Generated", + "Identity") })); - return new TokenDto(token, user.RefreshToken, user.RefreshTokenExpiryTime); } @@ -126,8 +137,8 @@ private string GenerateEncryptedToken(SigningCredentials signingCredentials, IEn claims: claims, expires: DateTime.UtcNow.AddMinutes(_jwtOptions.TokenExpirationInMinutes), signingCredentials: signingCredentials, - issuer: JwtAuthConstants.Issuer, - audience: JwtAuthConstants.Audience + issuer: _jwtOptions.Issuer, + audience: _jwtOptions.Audience ); var tokenHandler = new JwtSecurityTokenHandler(); return tokenHandler.WriteToken(token); @@ -164,8 +175,8 @@ private ClaimsPrincipal GetPrincipalFromExpiredToken(string token) IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Key)), ValidateIssuer = true, ValidateAudience = true, - ValidAudience = JwtAuthConstants.Audience, - ValidIssuer = JwtAuthConstants.Issuer, + ValidAudience = _jwtOptions.Audience, + ValidIssuer = _jwtOptions.Issuer, RoleClaimType = ClaimTypes.Role, ClockSkew = TimeSpan.Zero, ValidateLifetime = false diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Password.cs b/src/framework/Identity/Services/UserService.Password.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Password.cs rename to src/framework/Identity/Services/UserService.Password.cs diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs b/src/framework/Identity/Services/UserService.Permissions.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.Permissions.cs rename to src/framework/Identity/Services/UserService.Permissions.cs diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.cs b/src/framework/Identity/Services/UserService.cs similarity index 98% rename from src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.cs rename to src/framework/Identity/Services/UserService.cs index fc5168004..563cd2568 100644 --- a/src/framework/Modules/Identity/Identity.Infrastructure/Users/UserService.cs +++ b/src/framework/Identity/Services/UserService.cs @@ -305,9 +305,9 @@ public async Task AssignRolesAsync(string userId, AssignUserRoleCommand } - public async Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken) + public async Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken) { - var userRoles = new List(); + var userRoles = new List(); var user = await userManager.FindByIdAsync(userId); if (user is null) throw new NotFoundException("user not found"); @@ -315,7 +315,7 @@ public async Task> GetUserRolesAsync(string userId, Canc if (roles is null) throw new NotFoundException("roles not found"); foreach (var role in roles) { - userRoles.Add(new UserRoleDetailDto + userRoles.Add(new UserRoleDto { RoleId = role.Id, RoleName = role.Name, diff --git a/src/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs b/src/framework/Identity/v1/RoleClaims/FshRoleClaim.cs similarity index 76% rename from src/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs rename to src/framework/Identity/v1/RoleClaims/FshRoleClaim.cs index 210fa1bec..3df953852 100644 --- a/src/framework/Infrastructure/Identity/RoleClaims/FshRoleClaim.cs +++ b/src/framework/Identity/v1/RoleClaims/FshRoleClaim.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Identity; -namespace FSH.Framework.Infrastructure.Identity.RoleClaims; +namespace FSH.Framework.Identity.v1.RoleClaims; public class FshRoleClaim : IdentityRoleClaim { public string? CreatedBy { get; init; } diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Roles/FshRole.cs b/src/framework/Identity/v1/Roles/FshRole.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Roles/FshRole.cs rename to src/framework/Identity/v1/Roles/FshRole.cs diff --git a/src/framework/Infrastructure/Identity/Roles/RoleService.cs b/src/framework/Identity/v1/Roles/RoleService.cs similarity index 81% rename from src/framework/Infrastructure/Identity/Roles/RoleService.cs rename to src/framework/Identity/v1/Roles/RoleService.cs index 1b6020853..fe4f21f75 100644 --- a/src/framework/Infrastructure/Identity/Roles/RoleService.cs +++ b/src/framework/Identity/v1/Roles/RoleService.cs @@ -1,13 +1,14 @@ using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.ExecutionContext; -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Core.Identity.Roles.Features.CreateOrUpdateRole; -using FSH.Framework.Core.Identity.Roles.Features.UpdatePermissions; -using FSH.Framework.Infrastructure.Identity.Persistence; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; +using FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; +using FSH.Framework.Identity.Infrastructure.Data; +using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Infrastructure.Identity.RoleClaims; -using FSH.Framework.Infrastructure.Tenant; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Shared.Constants; +using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; @@ -36,7 +37,7 @@ public async Task> GetRolesAsync() return new RoleDto { Id = role.Id, Name = role.Name!, Description = role.Description }; } - public async Task CreateOrUpdateRoleAsync(CreateOrUpdateRoleCommand command) + public async Task CreateOrUpdateRoleAsync(UpsertRoleCommand command) { FshRole? role = await _roleManager.FindByIdAsync(command.Id); @@ -77,36 +78,36 @@ public async Task GetWithPermissionsAsync(string id, CancellationToken return role; } - public async Task UpdatePermissionsAsync(UpdatePermissionsCommand request) + public async Task UpdatePermissionsAsync(UpdatePermissionsCommand command) { - var role = await _roleManager.FindByIdAsync(request.RoleId); + var role = await _roleManager.FindByIdAsync(command.RoleId); _ = role ?? throw new NotFoundException("role not found"); if (role.Name == FshRoles.Admin) { - throw new FshException("operation not permitted"); + throw new CustomException("operation not permitted"); } if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id != TenantConstants.Root.Id) { // Remove Root Permissions if the Role is not created for Root Tenant. - request.Permissions.RemoveAll(u => u.StartsWith("Permissions.Root.", StringComparison.InvariantCultureIgnoreCase)); + command.Permissions.RemoveAll(u => u.StartsWith("Permissions.Root.", StringComparison.InvariantCultureIgnoreCase)); } var currentClaims = await _roleManager.GetClaimsAsync(role); // Remove permissions that were previously selected - foreach (var claim in currentClaims.Where(c => !request.Permissions.Exists(p => p == c.Value))) + foreach (var claim in currentClaims.Where(c => !command.Permissions.Exists(p => p == c.Value))) { var result = await _roleManager.RemoveClaimAsync(role, claim); if (!result.Succeeded) { var errors = result.Errors.Select(error => error.Description).ToList(); - throw new FshException("operation failed", errors); + throw new CustomException("operation failed", errors); } } // Add all permissions that were not previously selected - foreach (string permission in request.Permissions.Where(c => !currentClaims.Any(p => p.Value == c))) + foreach (string permission in command.Permissions.Where(c => !currentClaims.Any(p => p.Value == c))) { if (!string.IsNullOrEmpty(permission)) { diff --git a/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs b/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs new file mode 100644 index 000000000..24bfc026f --- /dev/null +++ b/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs @@ -0,0 +1,19 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Contracts.v1.Tokens.RefreshToken; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Shared.Extensions; +using Microsoft.AspNetCore.Http; + +namespace FSH.Framework.Identity.v1.Tokens.RefreshToken; +internal class RefreshTokenCommandHandler( + ITokenService tokenService, + HttpContext context) + : ICommandHandler +{ + public async Task HandleAsync(RefreshTokenCommand command, CancellationToken cancellationToken = default) + { + string ip = context.GetIpAddress(); + var token = await tokenService.RefreshTokenAsync(command.Token, command.RefreshToken, ip, cancellationToken); + return new RefreshTokenCommandResponse(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); + } +} \ No newline at end of file diff --git a/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs b/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs new file mode 100644 index 000000000..de791bcb6 --- /dev/null +++ b/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs @@ -0,0 +1,12 @@ +using FluentValidation; +using FSH.Framework.Identity.Core.Tokens; + +namespace FSH.Framework.Identity.v1.Tokens.RefreshToken; +internal class RefreshTokenCommandValidator : AbstractValidator +{ + public RefreshTokenCommandValidator() + { + RuleFor(p => p.Token).Cascade(CascadeMode.Stop).NotEmpty(); + RuleFor(p => p.RefreshToken).Cascade(CascadeMode.Stop).NotEmpty(); + } +} diff --git a/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs b/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs new file mode 100644 index 000000000..2b4eeb011 --- /dev/null +++ b/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs @@ -0,0 +1,26 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Core.Tokens; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Identity.v1.Tokens.RefreshToken; +public static class RefreshTokenEndpoint +{ + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/refresh", async (RefreshTokenCommand command, + string tenant, + ICommandDispatcher dispatcher, + HttpContext context, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync(command, cancellationToken); + return TypedResults.Ok(result); + }) + .WithName(nameof(RefreshTokenEndpoint)) + .WithSummary("refresh JWTs") + .WithDescription("refresh JWTs") + .AllowAnonymous(); + } +} diff --git a/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs b/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs new file mode 100644 index 000000000..0d40c70ec --- /dev/null +++ b/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs @@ -0,0 +1,17 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; +using FSH.Framework.Identity.Core.Tokens; +using FSH.Framework.Shared.Extensions; +using Microsoft.AspNetCore.Http; + +namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; +internal class TokenGenerationCommandHandler(ITokenService tokenService, HttpContext context) + : ICommandHandler +{ + public async Task HandleAsync(TokenGenerationCommand command, CancellationToken cancellationToken = default) + { + string ip = context.GetIpAddress(); + var token = await tokenService.GenerateTokenAsync(command.Email, command.Password, ip, cancellationToken); + return new TokenGenerationCommandResponse(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); + } +} diff --git a/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs b/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs new file mode 100644 index 000000000..1e85881e0 --- /dev/null +++ b/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; + +namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; +internal class TokenGenerationCommandValidator : AbstractValidator +{ + public TokenGenerationCommandValidator() + { + RuleFor(p => p.Email) + .Cascade(CascadeMode.Stop) + .NotEmpty() + .EmailAddress(); + + RuleFor(p => p.Password) + .Cascade(CascadeMode.Stop) + .NotEmpty(); + } +} \ No newline at end of file diff --git a/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs b/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs new file mode 100644 index 000000000..d7106bb93 --- /dev/null +++ b/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs @@ -0,0 +1,27 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; +public static class TokenGenerationEndpoint +{ + internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/", async ( + TokenGenerationCommand command, + string tenant, + ICommandDispatcher dispatcher, + HttpContext context, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync(command, cancellationToken); + return TypedResults.Ok(result); + }) + .WithName(nameof(TokenGenerationEndpoint)) + .WithSummary("Generate JWTs") + .WithDescription("Generates access and refresh tokens.") + .AllowAnonymous(); + } +} diff --git a/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs b/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs new file mode 100644 index 000000000..8de36bf1e --- /dev/null +++ b/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs @@ -0,0 +1,13 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; +using FSH.Framework.Identity.Core.Users; + +namespace FSH.Framework.Identity.v1.Users.AssignUserRoles; +internal class AssignUserRolesCommandHandler(IUserService _userService) + : ICommandHandler +{ + public async Task HandleAsync( + AssignUserRolesCommand request, + CancellationToken cancellationToken = default) => + await _userService.AssignRolesAsync(request.UserId, request.UserRoles, cancellationToken); +} \ No newline at end of file diff --git a/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs b/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs new file mode 100644 index 000000000..2fa5c7d58 --- /dev/null +++ b/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs @@ -0,0 +1,25 @@ +using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Framework.Identity.v1.Users.AssignUserRoles; +public static class AssignUserRolesEndpoint +{ + internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints.MapPost("/{id:guid}/roles", async (AssignUserRolesCommand command, + HttpContext context, + string id, + ICommandDispatcher dispatcher, + CancellationToken cancellationToken) => + { + var result = await dispatcher.SendAsync(command, cancellationToken); + return Results.Ok(result); + }) + .WithName(nameof(AssignUserRolesEndpoint)) + .WithSummary("assign roles") + .WithDescription("assign roles"); + } +} diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs b/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs similarity index 90% rename from src/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs rename to src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs index 7164ac566..5552a5cfc 100644 --- a/src/framework/Infrastructure/Identity/Users/Endpoints/ChangePasswordEndpoint.cs +++ b/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs @@ -1,9 +1,9 @@ using FluentValidation; using FluentValidation.Results; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.ChangePassword; using FSH.Framework.Core.Origin; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Contracts.v1.Users.ChangePassword; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ChangePassword/ChangePasswordValidator.cs rename to src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/ConfirmEmailEndpoint.cs b/src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/ConfirmEmailEndpoint.cs rename to src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/DeleteUserEndpoint.cs b/src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/DeleteUserEndpoint.cs rename to src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs b/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs similarity index 62% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs rename to src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs index f8418a60e..13b54d277 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ForgotPassword/ForgotPasswordValidator.cs +++ b/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs @@ -1,9 +1,9 @@ using FluentValidation; namespace FSH.Framework.Identity.Endpoints.v1.Users.ForgotPassword; -public class ForgotPasswordValidator : AbstractValidator +public class ForgotPasswordCommandValidator : AbstractValidator { - public ForgotPasswordValidator() + public ForgotPasswordCommandValidator() { RuleFor(p => p.Email).Cascade(CascadeMode.Stop) .NotEmpty() diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/ForgotPasswordEndpoint.cs b/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/ForgotPasswordEndpoint.cs rename to src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Users/FshUser.cs b/src/framework/Identity/v1/Users/FshUser.cs similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Users/FshUser.cs rename to src/framework/Identity/v1/Users/FshUser.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserEndpoint.cs b/src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/GetUserEndpoint.cs rename to src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserPermissionsEndpoint.cs b/src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/GetUserPermissionsEndpoint.cs rename to src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserProfileEndpoint.cs b/src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/GetUserProfileEndpoint.cs rename to src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs b/src/framework/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs similarity index 86% rename from src/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs rename to src/framework/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs index 757f84292..b3a2bc940 100644 --- a/src/framework/Infrastructure/Identity/Users/Endpoints/GetUserRolesEndpoint.cs +++ b/src/framework/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/GetUsersListEndpoint.cs b/src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/GetUsersListEndpoint.cs rename to src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/RegisterUserEndpoint.cs b/src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/RegisterUserEndpoint.cs rename to src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs b/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs similarity index 66% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs rename to src/framework/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs index 8ee889e44..9917e3cce 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/ResetPassword/ResetPasswordValidator.cs +++ b/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs @@ -2,9 +2,9 @@ namespace FSH.Framework.Identity.Endpoints.v1.Users.ResetPassword; -public class ResetPasswordValidator : AbstractValidator +public class ResetPasswordCommandValidator : AbstractValidator { - public ResetPasswordValidator() + public ResetPasswordCommandValidator() { RuleFor(x => x.Email).NotEmpty().EmailAddress(); RuleFor(x => x.Password).NotEmpty(); diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/ResetPasswordEndpoint.cs b/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/ResetPasswordEndpoint.cs rename to src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/SelfRegisterUserEndpoint.cs b/src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/SelfRegisterUserEndpoint.cs rename to src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/ToggleUserStatusEndpoint.cs b/src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/ToggleUserStatusEndpoint.cs rename to src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs similarity index 91% rename from src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs rename to src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs index 81b0e1752..dbfd12253 100644 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/UpdateUser/UpdateUserCommandValidator.cs +++ b/src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs @@ -1,7 +1,8 @@ using FluentValidation; using FSH.Framework.Core.Storage; +using FSH.Framework.Identity.Endpoints.v1.Users.UpdateUser; -namespace FSH.Framework.Identity.Endpoints.v1.Users.UpdateUser; +namespace FSH.Framework.Identity.v1.Users.UpdateUser; public class UpdateUserCommandValidator : AbstractValidator { public UpdateUserCommandValidator() diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/UpdateUserEndpoint.cs b/src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/Identity/Users/Endpoints/UpdateUserEndpoint.cs rename to src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs index 865bce172..634c81a62 100644 --- a/src/framework/Infrastructure/Extensions.cs +++ b/src/framework/Infrastructure/Extensions.cs @@ -1,15 +1,11 @@ -using System.Reflection; -using Asp.Versioning.Conventions; +using Asp.Versioning.Conventions; using FluentValidation; using FSH.Framework.Core; using FSH.Framework.Core.Origin; -using FSH.Framework.Infrastructure.Auth; using FSH.Framework.Infrastructure.Auth.Jwt; -using FSH.Framework.Infrastructure.Behaviours; using FSH.Framework.Infrastructure.Caching; using FSH.Framework.Infrastructure.Cors; using FSH.Framework.Infrastructure.Exceptions; -using FSH.Framework.Infrastructure.Identity; using FSH.Framework.Infrastructure.Jobs; using FSH.Framework.Infrastructure.Logging.Serilog; using FSH.Framework.Infrastructure.Mail; @@ -17,15 +13,12 @@ using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Infrastructure.RateLimit; using FSH.Framework.Infrastructure.SecurityHeaders; -using FSH.Framework.Infrastructure.Storage.Files; -using FSH.Framework.Infrastructure.Tenant; -using FSH.Framework.Infrastructure.Tenant.Endpoints; -using FSH.Starter.Aspire.ServiceDefaults; -using MediatR; +using FSH.Framework.Infrastructure.Storage; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using System.Reflection; namespace FSH.Framework.Infrastructure; @@ -34,13 +27,10 @@ public static class Extensions public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBuilder builder) { ArgumentNullException.ThrowIfNull(builder); - builder.AddServiceDefaults(); builder.ConfigureSerilog(); builder.ConfigureDatabase(); - builder.Services.ConfigureMultitenancy(); - builder.Services.ConfigureIdentity(); builder.Services.AddCorsPolicy(builder.Configuration); - builder.Services.ConfigureFileStorage(); + builder.Services.ConfigureLocalFileStorage(); builder.Services.ConfigureJwtAuth(); builder.Services.ConfigureOpenApi(); builder.Services.ConfigureJobs(builder.Configuration); @@ -61,13 +51,6 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui // Register validators builder.Services.AddValidatorsFromAssemblies(assemblies); - // Register MediatR - builder.Services.AddMediatR(cfg => - { - cfg.RegisterServicesFromAssemblies(assemblies); - cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>)); - }); - builder.Services.ConfigureRateLimit(builder.Configuration); builder.Services.ConfigureSecurityHeaders(builder.Configuration); @@ -76,10 +59,8 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui public static WebApplication UseFshFramework(this WebApplication app) { - app.MapDefaultEndpoints(); app.UseRateLimit(); app.UseSecurityHeaders(); - app.UseMultitenancy(); app.UseExceptionHandler(); app.UseCorsPolicy(); app.UseOpenApi(); @@ -93,11 +74,6 @@ public static WebApplication UseFshFramework(this WebApplication app) }); app.UseAuthentication(); app.UseAuthorization(); - app.MapTenantEndpoints(); - app.MapIdentityEndpoints(); - - // Current user middleware - app.UseMiddleware(); // Register API versions var versions = app.NewApiVersionSet() diff --git a/src/framework/Infrastructure/Identity/Extensions.cs b/src/framework/Infrastructure/Identity/Extensions.cs deleted file mode 100644 index aa70ce357..000000000 --- a/src/framework/Infrastructure/Identity/Extensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using FSH.Framework.Core.Audit; -using FSH.Framework.Core.ExecutionContext; -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Core.Identity.Tokens; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Persistence; -using FSH.Framework.Infrastructure.Auth; -using FSH.Framework.Infrastructure.Identity.Audit; -using FSH.Framework.Infrastructure.Identity.Persistence; -using FSH.Framework.Infrastructure.Identity.Roles; -using FSH.Framework.Infrastructure.Identity.Roles.Endpoints; -using FSH.Framework.Infrastructure.Identity.Tokens; -using FSH.Framework.Infrastructure.Identity.Tokens.Endpoints; -using FSH.Framework.Infrastructure.Identity.Users; -using FSH.Framework.Infrastructure.Identity.Users.Endpoints; -using FSH.Framework.Infrastructure.Identity.Users.Services; -using FSH.Framework.Infrastructure.Persistence; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using IdentityConstants = FSH.Starter.Shared.Authorization.IdentityConstants; - -namespace FSH.Framework.Infrastructure.Identity; -internal static class Extensions -{ - internal static IServiceCollection ConfigureIdentity(this IServiceCollection services) - { - ArgumentNullException.ThrowIfNull(services); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(sp => (ICurrentUserInitializer)sp.GetRequiredService()); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.BindDbContext(); - services.AddScoped(); - services.AddIdentity(options => - { - options.Password.RequiredLength = IdentityConstants.PasswordLength; - options.Password.RequireDigit = false; - options.Password.RequireLowercase = false; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequireUppercase = false; - options.User.RequireUniqueEmail = true; - }) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - return services; - } - - public static IEndpointRouteBuilder MapIdentityEndpoints(this IEndpointRouteBuilder app) - { - var users = app.MapGroup("api/users").WithTags("users"); - users.MapUserEndpoints(); - - var tokens = app.MapGroup("api/token").WithTags("token"); - tokens.MapTokenEndpoints(); - - var roles = app.MapGroup("api/roles").WithTags("roles"); - roles.MapRoleEndpoints(); - - return app; - } -} diff --git a/src/framework/Infrastructure/Identity/Roles/FshRole.cs b/src/framework/Infrastructure/Identity/Roles/FshRole.cs deleted file mode 100644 index fa8baf6bc..000000000 --- a/src/framework/Infrastructure/Identity/Roles/FshRole.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.AspNetCore.Identity; - -namespace FSH.Framework.Infrastructure.Identity.Roles; -public class FshRole : IdentityRole -{ - public string? Description { get; set; } - - public FshRole(string name, string? description = null) - : base(name) - { - Description = description; - NormalizedName = name.ToUpperInvariant(); - } -} diff --git a/src/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs b/src/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs deleted file mode 100644 index 3bd70a42c..000000000 --- a/src/framework/Infrastructure/Identity/Tokens/Endpoints/Extensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Identity.Tokens.Endpoints; -internal static class Extensions -{ - public static IEndpointRouteBuilder MapTokenEndpoints(this IEndpointRouteBuilder app) - { - app.MapRefreshTokenEndpoint(); - app.MapTokenGenerationEndpoint(); - return app; - } - - public static string GetIpAddress(this HttpContext context) - { - string ip = "N/A"; - if (context.Request.Headers.TryGetValue("X-Forwarded-For", out var ipList)) - { - ip = ipList.FirstOrDefault() ?? "N/A"; - } - else if (context.Connection.RemoteIpAddress != null) - { - ip = context.Connection.RemoteIpAddress.MapToIPv4().ToString(); - } - return ip; - - } -} diff --git a/src/framework/Infrastructure/Identity/Tokens/TokenService.cs b/src/framework/Infrastructure/Identity/Tokens/TokenService.cs deleted file mode 100644 index 4f0bc6014..000000000 --- a/src/framework/Infrastructure/Identity/Tokens/TokenService.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Security.Cryptography; -using System.Text; -using Finbuckle.MultiTenant.Abstractions; -using FSH.Framework.Core.Auth.Jwt; -using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.Identity.Tokens; -using FSH.Framework.Core.Identity.Tokens.Features.Generate; -using FSH.Framework.Core.Identity.Tokens.Features.Refresh; -using FSH.Framework.Core.Identity.Tokens.Models; -using FSH.Framework.Infrastructure.Auth.Jwt; -using FSH.Framework.Infrastructure.Identity.Audit; -using FSH.Framework.Infrastructure.Identity.Users; -using FSH.Framework.Infrastructure.Tenant; -using FSH.Starter.Shared.Authorization; -using MediatR; -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; - -namespace FSH.Framework.Infrastructure.Identity.Tokens; -public sealed class TokenService : ITokenService -{ - private readonly UserManager _userManager; - private readonly IMultiTenantContextAccessor? _multiTenantContextAccessor; - private readonly JwtOptions _jwtOptions; - private readonly IPublisher _publisher; - public TokenService(IOptions jwtOptions, UserManager userManager, IMultiTenantContextAccessor? multiTenantContextAccessor, IPublisher publisher) - { - _jwtOptions = jwtOptions.Value; - _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); - _multiTenantContextAccessor = multiTenantContextAccessor; - _publisher = publisher; - } - - public async Task GenerateTokenAsync(TokenGenerationCommand request, string ipAddress, CancellationToken cancellationToken) - { - var currentTenant = _multiTenantContextAccessor!.MultiTenantContext.TenantInfo; - if (currentTenant == null) throw new UnauthorizedException(); - if (string.IsNullOrWhiteSpace(currentTenant.Id) - || await _userManager.FindByEmailAsync(request.Email.Trim().Normalize()) is not { } user - || !await _userManager.CheckPasswordAsync(user, request.Password)) - { - throw new UnauthorizedException(); - } - - if (!user.IsActive) - { - throw new UnauthorizedException("user is deactivated"); - } - - if (!user.EmailConfirmed) - { - throw new UnauthorizedException("email not confirmed"); - } - - if (currentTenant.Id != TenantConstants.Root.Id) - { - if (!currentTenant.IsActive) - { - throw new UnauthorizedException($"tenant {currentTenant.Id} is deactivated"); - } - - if (DateTime.UtcNow > currentTenant.ValidUpto) - { - throw new UnauthorizedException($"tenant {currentTenant.Id} validity has expired"); - } - } - - return await GenerateTokensAndUpdateUser(user, ipAddress); - } - - - public async Task RefreshTokenAsync(RefreshTokenCommand request, string ipAddress, CancellationToken cancellationToken) - { - var userPrincipal = GetPrincipalFromExpiredToken(request.Token); - var userId = _userManager.GetUserId(userPrincipal)!; - var user = await _userManager.FindByIdAsync(userId); - if (user is null) - { - throw new UnauthorizedException(); - } - - if (user.RefreshToken != request.RefreshToken || user.RefreshTokenExpiryTime <= DateTime.UtcNow) - { - throw new UnauthorizedException("Invalid Refresh Token"); - } - - return await GenerateTokensAndUpdateUser(user, ipAddress); - } - private async Task GenerateTokensAndUpdateUser(FshUser user, string ipAddress) - { - string token = GenerateJwt(user, ipAddress); - - user.RefreshToken = GenerateRefreshToken(); - user.RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(_jwtOptions.RefreshTokenExpirationInDays); - - await _userManager.UpdateAsync(user); - - await _publisher.Publish(new AuditPublishedEvent(new() - { - new() - { - Id = Guid.NewGuid(), - Operation = "Token Generated", - Entity = "Identity", - UserId = new Guid(user.Id), - DateTime = DateTime.UtcNow, - } - })); - - return new TokenResponse(token, user.RefreshToken, user.RefreshTokenExpiryTime); - } - - private string GenerateJwt(FshUser user, string ipAddress) => - GenerateEncryptedToken(GetSigningCredentials(), GetClaims(user, ipAddress)); - - private SigningCredentials GetSigningCredentials() - { - byte[] secret = Encoding.UTF8.GetBytes(_jwtOptions.Key); - return new SigningCredentials(new SymmetricSecurityKey(secret), SecurityAlgorithms.HmacSha256); - } - - private string GenerateEncryptedToken(SigningCredentials signingCredentials, IEnumerable claims) - { - var token = new JwtSecurityToken( - claims: claims, - expires: DateTime.UtcNow.AddMinutes(_jwtOptions.TokenExpirationInMinutes), - signingCredentials: signingCredentials, - issuer: JwtAuthConstants.Issuer, - audience: JwtAuthConstants.Audience - ); - var tokenHandler = new JwtSecurityTokenHandler(); - return tokenHandler.WriteToken(token); - } - - private List GetClaims(FshUser user, string ipAddress) => - new List - { - new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - new(ClaimTypes.NameIdentifier, user.Id), - new(ClaimTypes.Email, user.Email!), - new(ClaimTypes.Name, user.FirstName ?? string.Empty), - new(ClaimTypes.MobilePhone, user.PhoneNumber ?? string.Empty), - new(FshClaims.Fullname, $"{user.FirstName} {user.LastName}"), - new(ClaimTypes.Surname, user.LastName ?? string.Empty), - new(FshClaims.IpAddress, ipAddress), - new(FshClaims.Tenant, _multiTenantContextAccessor!.MultiTenantContext.TenantInfo!.Id), - new(FshClaims.ImageUrl, user.ImageUrl == null ? string.Empty : user.ImageUrl.ToString()) - }; - private static string GenerateRefreshToken() - { - byte[] randomNumber = new byte[32]; - using var rng = RandomNumberGenerator.Create(); - rng.GetBytes(randomNumber); - return Convert.ToBase64String(randomNumber); - } - - private ClaimsPrincipal GetPrincipalFromExpiredToken(string token) - { -#pragma warning disable CA5404 // Do not disable token validation checks - var tokenValidationParameters = new TokenValidationParameters - { - ValidateIssuerSigningKey = true, - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Key)), - ValidateIssuer = true, - ValidateAudience = true, - ValidAudience = JwtAuthConstants.Audience, - ValidIssuer = JwtAuthConstants.Issuer, - RoleClaimType = ClaimTypes.Role, - ClockSkew = TimeSpan.Zero, - ValidateLifetime = false - }; -#pragma warning restore CA5404 // Do not disable token validation checks - var tokenHandler = new JwtSecurityTokenHandler(); - var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken); - if (securityToken is not JwtSecurityToken jwtSecurityToken || - !jwtSecurityToken.Header.Alg.Equals( - SecurityAlgorithms.HmacSha256, - StringComparison.OrdinalIgnoreCase)) - { - throw new UnauthorizedException("invalid token"); - } - - return principal; - } -} diff --git a/src/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs b/src/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs deleted file mode 100644 index cbc311c6b..000000000 --- a/src/framework/Infrastructure/Identity/Users/Endpoints/Extensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using FSH.Framework.Infrastructure.Identity.Audit.Endpoints; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Identity.Users.Endpoints; -internal static class Extensions -{ - public static IEndpointRouteBuilder MapUserEndpoints(this IEndpointRouteBuilder app) - { - app.MapRegisterUserEndpoint(); - app.MapSelfRegisterUserEndpoint(); - app.MapUpdateUserEndpoint(); - app.MapGetUsersListEndpoint(); - app.MapDeleteUserEndpoint(); - app.MapForgotPasswordEndpoint(); - app.MapChangePasswordEndpoint(); - app.MapResetPasswordEndpoint(); - app.MapGetMeEndpoint(); - app.MapGetUserEndpoint(); - app.MapGetCurrentUserPermissionsEndpoint(); - app.ToggleUserStatusEndpointEndpoint(); - app.MapAssignRolesToUserEndpoint(); - app.MapGetUserRolesEndpoint(); - app.MapGetUserAuditTrailEndpoint(); - app.MapConfirmEmailEndpoint(); - return app; - } -} diff --git a/src/framework/Infrastructure/Infrastructure.csproj b/src/framework/Infrastructure/Infrastructure.csproj index 5b8ddef5b..d152b6a19 100644 --- a/src/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Infrastructure/Infrastructure.csproj @@ -58,6 +58,7 @@ + diff --git a/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs b/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs index 4fc0bcbed..c8ec9f657 100644 --- a/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs +++ b/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs @@ -10,12 +10,12 @@ public class InMemoryEventPublisher : IEventPublisher public InMemoryEventPublisher(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; - public async Task PublishAsync(TEvent @event, CancellationToken cancellationToken = default) + public async Task PublishAsync(IEvent appEvent, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(@event); + ArgumentNullException.ThrowIfNull(appEvent); using var scope = _serviceProvider.CreateScope(); - var handlers = scope.ServiceProvider.GetServices>(); + var handlers = scope.ServiceProvider.GetServices>(); foreach (var handler in handlers) { @@ -27,14 +27,14 @@ public async Task PublishAsync(TEvent @event, CancellationToken cancella try { attempt++; - await handler.HandleAsync(@event, cancellationToken); + await handler.HandleAsync(appEvent, cancellationToken); break; // Success } catch (Exception ex) { if (attempt == maxAttempts) { - Console.WriteLine($"Handler for {typeof(TEvent).Name} failed after {attempt} attempts: {ex.Message}"); + Console.WriteLine($"Handler for {typeof(IEvent).Name} failed after {attempt} attempts: {ex.Message}"); // Optionally: Add to dead-letter queue } else diff --git a/src/framework/Infrastructure/Modules/Extensions.cs b/src/framework/Infrastructure/Modules/Extensions.cs new file mode 100644 index 000000000..d51d2d60b --- /dev/null +++ b/src/framework/Infrastructure/Modules/Extensions.cs @@ -0,0 +1,42 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; + +namespace FSH.Framework.Infrastructure.Modules; +public static class Extensions +{ + public static IServiceCollection AddFrameworkModules( + this IServiceCollection services, + IConfiguration config, + params Assembly[] assemblies) + { + var moduleTypes = assemblies + .SelectMany(a => a.GetTypes()) + .Where(t => typeof(IFrameworkModule).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract) + .ToList(); + + foreach (var type in moduleTypes) + { + var module = (IFrameworkModule)Activator.CreateInstance(type)!; + module.AddModuleServices(services, config); + services.AddSingleton(module); // Store for endpoint mapping later + } + + return services; + } + + public static IApplicationBuilder MapFrameworkModuleEndpoints(this IApplicationBuilder app) + { + var modules = app.ApplicationServices.GetServices(); + var endpoints = app as IEndpointRouteBuilder; + + foreach (var module in modules) + { + module.MapEndpoints(endpoints!); + } + + return app; + } +} diff --git a/src/framework/Infrastructure/Modules/IFrameworkModule.cs b/src/framework/Infrastructure/Modules/IFrameworkModule.cs new file mode 100644 index 000000000..8e703df31 --- /dev/null +++ b/src/framework/Infrastructure/Modules/IFrameworkModule.cs @@ -0,0 +1,4 @@ +namespace FSH.Framework.Infrastructure.Modules; +public interface IFrameworkModule : IModule +{ +} diff --git a/src/framework/Infrastructure/Persistence/Extensions.cs b/src/framework/Infrastructure/Persistence/Extensions.cs index bfbd1270f..c3220abc6 100644 --- a/src/framework/Infrastructure/Persistence/Extensions.cs +++ b/src/framework/Infrastructure/Persistence/Extensions.cs @@ -10,7 +10,7 @@ namespace FSH.Framework.Infrastructure.Persistence; public static class Extensions { private static readonly ILogger Logger = Log.ForContext(typeof(Extensions)); - internal static DbContextOptionsBuilder ConfigureDatabase(this DbContextOptionsBuilder builder, string dbProvider, string connectionString) + public static DbContextOptionsBuilder ConfigureDatabase(this DbContextOptionsBuilder builder, string dbProvider, string connectionString) { builder.ConfigureWarnings(warnings => warnings.Log(RelationalEventId.PendingModelChangesWarning)); return dbProvider.ToUpperInvariant() switch diff --git a/src/framework/Infrastructure/Persistence/FshDbContext.cs b/src/framework/Infrastructure/Persistence/FshDbContext.cs index 8ed626083..ed22cd663 100644 --- a/src/framework/Infrastructure/Persistence/FshDbContext.cs +++ b/src/framework/Infrastructure/Persistence/FshDbContext.cs @@ -3,6 +3,7 @@ using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.Messaging.Events; using FSH.Framework.Core.Persistence; +using FSH.Framework.Shared.Multitenancy; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; diff --git a/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs b/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs index 0aa07f569..f7ba3b03b 100644 --- a/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs +++ b/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs @@ -1,11 +1,10 @@ using FSH.Framework.Core.Storage; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace FSH.Framework.Infrastructure.Storage; public static class StorageServiceRegistration { - public static IServiceCollection AddFileStorage(this IServiceCollection services, IConfiguration config) + public static IServiceCollection ConfigureLocalFileStorage(this IServiceCollection services) { // You can later use config["Storage:Provider"] to swap between implementations services.AddScoped(); diff --git a/src/framework/Infrastructure/Tenant/Extensions.cs b/src/framework/Infrastructure/Tenant/Extensions.cs deleted file mode 100644 index f5e3fe398..000000000 --- a/src/framework/Infrastructure/Tenant/Extensions.cs +++ /dev/null @@ -1,133 +0,0 @@ -using Finbuckle.MultiTenant; -using Finbuckle.MultiTenant.Abstractions; -using Finbuckle.MultiTenant.Stores.DistributedCacheStore; -using FSH.Framework.Core.Persistence; -using FSH.Framework.Core.Tenant.Abstractions; -using FSH.Framework.Infrastructure.Persistence; -using FSH.Framework.Infrastructure.Persistence.Services; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Serilog; - -namespace FSH.Framework.Infrastructure.Tenant; -internal static class Extensions -{ - public static IServiceCollection ConfigureMultitenancy(this IServiceCollection services) - { - ArgumentNullException.ThrowIfNull(services); - services.AddTransient(); - services.BindDbContext(); - services - .AddMultiTenant(config => - { - // to save database calls to resolve tenant - // this was happening for every request earlier, leading to ineffeciency - config.Events.OnTenantResolveCompleted = async (context) => - { - if (context.MultiTenantContext.StoreInfo is null) return; - if (context.MultiTenantContext.StoreInfo.StoreType != typeof(DistributedCacheStore)) - { - var sp = ((HttpContext)context.Context!).RequestServices; - var distributedCacheStore = sp - .GetService>>()! - .FirstOrDefault(s => s.GetType() == typeof(DistributedCacheStore)); - - await distributedCacheStore!.TryAddAsync(context.MultiTenantContext.TenantInfo!); - } - await Task.FromResult(0); - }; - }) - .WithClaimStrategy(FshClaims.Tenant) - .WithHeaderStrategy(TenantConstants.Identifier) - .WithDelegateStrategy(async context => - { - if (context is not HttpContext httpContext) - return null; - if (!httpContext.Request.Query.TryGetValue("tenant", out var tenantIdentifier) || string.IsNullOrEmpty(tenantIdentifier)) - return null; - return await Task.FromResult(tenantIdentifier.ToString()); - }) - .WithDistributedCacheStore(TimeSpan.FromMinutes(60)) - .WithEFCoreStore(); - services.AddScoped(); - return services; - } - - public static WebApplication UseMultitenancy(this WebApplication app) - { - ArgumentNullException.ThrowIfNull(app); - app.UseMultiTenant(); - - // set up tenant store - var tenants = TenantStoreSetup(app); - - // set up tenant databases - app.SetupTenantDatabases(tenants); - - return app; - } - - private static IApplicationBuilder SetupTenantDatabases(this IApplicationBuilder app, IEnumerable tenants) - { - foreach (var tenant in tenants) - { - // create a scope for tenant - using var tenantScope = app.ApplicationServices.CreateScope(); - - //set current tenant so that the right connection string is used - tenantScope.ServiceProvider.GetRequiredService() - .MultiTenantContext = new MultiTenantContext() - { - TenantInfo = tenant - }; - - // using the scope, perform migrations / seeding - var initializers = tenantScope.ServiceProvider.GetServices(); - foreach (var initializer in initializers) - { - initializer.MigrateAsync(CancellationToken.None).Wait(); - initializer.SeedAsync(CancellationToken.None).Wait(); - } - } - return app; - } - - private static IEnumerable TenantStoreSetup(IApplicationBuilder app) - { - var scope = app.ApplicationServices.CreateScope(); - - // tenant master schema migration - var tenantDbContext = scope.ServiceProvider.GetRequiredService(); - if (tenantDbContext.Database.GetPendingMigrations().Any()) - { - tenantDbContext.Database.Migrate(); - Log.Information("applied database migrations for tenant module"); - } - - // default tenant seeding - if (tenantDbContext.TenantInfo.Find(TenantConstants.Root.Id) is null) - { - var rootTenant = new FshTenantInfo( - TenantConstants.Root.Id, - TenantConstants.Root.Name, - string.Empty, - TenantConstants.Root.EmailAddress); - - rootTenant.SetValidity(DateTime.UtcNow.AddYears(1)); - tenantDbContext.TenantInfo.Add(rootTenant); - tenantDbContext.SaveChanges(); - Log.Information("configured default tenant data"); - } - - // get all tenants from store - var tenantStore = scope.ServiceProvider.GetRequiredService>(); - var tenants = tenantStore.GetAllAsync().Result; - - //dispose scope - scope.Dispose(); - - return tenants; - } -} diff --git a/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs b/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs index d6fc3bf60..b71f418bf 100644 --- a/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs +++ b/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs @@ -1,5 +1,4 @@ using FSH.Framework.Auditing.Contracts.Enums; -using System.Collections.ObjectModel; namespace FSH.Framework.Auditing.Contracts.Dtos; public record TrailDto( @@ -8,9 +7,9 @@ public record TrailDto( Guid UserId, AuditOperation Operation, string Description, - string EntityName, - Dictionary KeyValues, - Dictionary OldValues, - Dictionary NewValues, - Collection ModifiedProperties + string EntityName +//Dictionary KeyValues, +//Dictionary OldValues, +//Dictionary NewValues, +//Collection ModifiedProperties ); \ No newline at end of file diff --git a/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs b/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs index e5ccab4fe..c535a8684 100644 --- a/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs +++ b/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs @@ -3,7 +3,7 @@ namespace FSH.Framework.Auditing.Contracts.Events.IntegrationEvents; -public class AuditPublishedEvent : INotification +public class AuditPublishedEvent : IEvent { public IReadOnlyCollection Trails { get; } diff --git a/src/framework/Modules/Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/AuditingModule.cs index 9507ced59..55c49c4e2 100644 --- a/src/framework/Modules/Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/AuditingModule.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection; namespace FSH.Framework.Auditing.Endpoints; -public class AuditingModule : IModule +public class AuditingModule : IFrameworkModule { public IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config) { diff --git a/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs b/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs index 33bbce879..cec40ea07 100644 --- a/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs +++ b/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Auditing.Contracts.DomainEvents; +using FSH.Framework.Auditing.Contracts.Dtos; using FSH.Framework.Auditing.Contracts.Enums; -using FSH.Framework.Auditing.Features.Entities; +using FSH.Framework.Auditing.Contracts.Events.IntegrationEvents; using FSH.Framework.Core.Domain; using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.ExecutionContext; @@ -33,12 +33,12 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData, Cancell { if (eventData.Context == null) return; eventData.Context.ChangeTracker.DetectChanges(); - var trails = new List(); + var trails = new List(); var utcNow = timeProvider.GetUtcNow(); foreach (var entry in eventData.Context.ChangeTracker.Entries().Where(x => x.State is EntityState.Added or EntityState.Deleted or EntityState.Modified).ToList()) { var userId = currentUser.GetUserId(); - var audit = new Trail() + var audit = new TrailDto() { Id = Guid.NewGuid(), EntityName = entry.Entity.GetType().Name, diff --git a/src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs b/src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs deleted file mode 100644 index b7281618f..000000000 --- a/src/framework/Modules/Identity/Identity.Core/Roles/CreateOrUpdateRoleRequest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace FSH.Framework.Identity.Core.Roles; -public class CreateOrUpdateRoleRequest -{ -} diff --git a/src/framework/Modules/Identity/Identity.Core/Roles/IRoleService.cs b/src/framework/Modules/Identity/Identity.Core/Roles/IRoleService.cs deleted file mode 100644 index 243bc9b73..000000000 --- a/src/framework/Modules/Identity/Identity.Core/Roles/IRoleService.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace FSH.Framework.Identity.Core.Roles; - -public interface IRoleService -{ - Task> GetRolesAsync(); - Task GetRoleAsync(string id); - Task CreateOrUpdateRoleAsync(CreateOrUpdateRoleRequest request); - Task DeleteRoleAsync(string id); - Task GetWithPermissionsAsync(string id, CancellationToken cancellationToken); - - Task UpdatePermissionsAsync(UpdatePermissionsRequest request); -} - diff --git a/src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs b/src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs deleted file mode 100644 index d1ee944a8..000000000 --- a/src/framework/Modules/Identity/Identity.Core/Roles/UpdatePermissionsRequest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace FSH.Framework.Identity.Core.Roles; -public class UpdatePermissionsRequest -{ -} diff --git a/src/framework/Modules/Identity/Identity.Core/Tokens/ITokenService.cs b/src/framework/Modules/Identity/Identity.Core/Tokens/ITokenService.cs deleted file mode 100644 index 947ef8fab..000000000 --- a/src/framework/Modules/Identity/Identity.Core/Tokens/ITokenService.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FSH.Framework.Identity.Core.Tokens; -public interface ITokenService -{ - Task GenerateTokenAsync(TokenGenerationRequest request, string ipAddress, CancellationToken cancellationToken); - Task RefreshTokenAsync(TokenRefreshRequest request, string ipAddress, CancellationToken cancellationToken); -} diff --git a/src/framework/Modules/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs b/src/framework/Modules/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs deleted file mode 100644 index bf4e81b66..000000000 --- a/src/framework/Modules/Identity/Identity.Core/Tokens/TokenGenerationRequest.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Identity.Core.Tokens; -public record TokenGenerationRequest(string Email, string Password, string IpAddress); diff --git a/src/framework/Modules/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs b/src/framework/Modules/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs deleted file mode 100644 index 488801058..000000000 --- a/src/framework/Modules/Identity/Identity.Core/Tokens/TokenRefreshRequest.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace FSH.Framework.Identity.Core.Tokens; -public record TokenRefreshRequest(string Token, string RefreshToken); diff --git a/src/framework/Modules/Identity/Identity.Core/Users/IUserService.cs b/src/framework/Modules/Identity/Identity.Core/Users/IUserService.cs deleted file mode 100644 index a2a68e48c..000000000 --- a/src/framework/Modules/Identity/Identity.Core/Users/IUserService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using FSH.Framework.Identity.Core.Roles; -using System.Security.Claims; - -namespace FSH.Framework.Identity.Core.Users; -public interface IUserService -{ - Task ExistsWithNameAsync(string name); - Task ExistsWithEmailAsync(string email, string? exceptId = null); - Task ExistsWithPhoneNumberAsync(string phoneNumber, string? exceptId = null); - Task> GetListAsync(CancellationToken cancellationToken); - Task GetCountAsync(CancellationToken cancellationToken); - Task GetAsync(string userId, CancellationToken cancellationToken); - Task ToggleStatusAsync(ToggleUserStatusCommand request, CancellationToken cancellationToken); - Task GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal); - Task RegisterAsync(RegisterUserCommand request, string origin, CancellationToken cancellationToken); - Task UpdateAsync(UpdateUserCommand request, string userId); - Task DeleteAsync(string userId); - Task ConfirmEmailAsync(string userId, string code, string tenant, CancellationToken cancellationToken); - Task ConfirmPhoneNumberAsync(string userId, string code); - - // permisions - Task HasPermissionAsync(string userId, string permission, CancellationToken cancellationToken = default); - - // passwords - Task ForgotPasswordAsync(ForgotPasswordCommand request, string origin, CancellationToken cancellationToken); - Task ResetPasswordAsync(ResetPasswordCommand request, CancellationToken cancellationToken); - Task?> GetPermissionsAsync(string userId, CancellationToken cancellationToken); - - Task ChangePasswordAsync(ChangePasswordCommand request, string userId); - Task AssignRolesAsync(string userId, IReadOnlyList userRoles, CancellationToken cancellationToken); - Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken); -} diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs deleted file mode 100644 index e9aa43a68..000000000 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/RefreshToken.cs +++ /dev/null @@ -1,48 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Core.Tokens; -using FSH.Framework.Shared.Extensions; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens; -public static class RefreshToken -{ - public sealed record Command(string Token, string RefreshToken) : ICommand; - public sealed record Response(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); - public class Validator : AbstractValidator - { - public Validator() - { - RuleFor(p => p.Token).Cascade(CascadeMode.Stop).NotEmpty(); - RuleFor(p => p.RefreshToken).Cascade(CascadeMode.Stop).NotEmpty(); - } - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/refresh", async (Command command, - string tenant, - ICommandDispatcher dispatcher, - HttpContext context, - CancellationToken cancellationToken) => - { - var result = await dispatcher.SendAsync(command, cancellationToken); - return TypedResults.Ok(result); - }) - .WithName(nameof(RefreshToken)) - .WithSummary("refresh JWTs") - .WithDescription("refresh JWTs") - .AllowAnonymous(); - } - public sealed class Handler(ITokenService tokenService, HttpContext context) : ICommandHandler - { - public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) - { - var request = new TokenRefreshRequest(command.Token, command.RefreshToken); - string ip = context.GetIpAddress(); - var token = await tokenService.RefreshTokenAsync(request, ip, cancellationToken); - return new Response(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); - } - } -} diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs deleted file mode 100644 index 415919b8b..000000000 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Tokens/TokenGeneration.cs +++ /dev/null @@ -1,56 +0,0 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Core.Tokens; -using FSH.Framework.Shared.Extensions; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Identity.Endpoints.v1.Tokens; -public static class TokenGeneration -{ - public sealed record Command(string Email, string Password) : ICommand; - public sealed record Response(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); - public sealed class Validator : AbstractValidator - { - public Validator() - { - RuleFor(p => p.Email) - .Cascade(CascadeMode.Stop) - .NotEmpty() - .EmailAddress(); - - RuleFor(p => p.Password) - .Cascade(CascadeMode.Stop) - .NotEmpty(); - } - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/", async ( - Command command, - string tenant, - ICommandDispatcher dispatcher, - HttpContext context, - CancellationToken cancellationToken) => - { - var result = await dispatcher.SendAsync(command, cancellationToken); - return TypedResults.Ok(result); - }) - .WithName(nameof(TokenGeneration)) - .WithSummary("Generate JWTs") - .WithDescription("Generates access and refresh tokens.") - .AllowAnonymous(); - } - - public sealed class Handler(ITokenService tokenService, HttpContext context) : ICommandHandler - { - public async Task HandleAsync(Command command, CancellationToken cancellationToken = default) - { - var request = new TokenGenerationRequest(command.Email, command.Password); - string ip = context.GetIpAddress(); - var token = await tokenService.GenerateTokenAsync(request, ip, cancellationToken); - return new Response(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); - } - } -} diff --git a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs b/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs deleted file mode 100644 index 4c50ffc2d..000000000 --- a/src/framework/Modules/Identity/Identity.Endpoints/v1/Users/AssignUserRoles.cs +++ /dev/null @@ -1,36 +0,0 @@ -using FSH.Framework.Core.Identity.Users.Dtos; -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Core.Users; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Identity.Endpoints.v1.Users; -public static class AssignUserRoles -{ - public class Command : ICommand - { - public required string UserId { get; init; } - public IReadOnlyList UserRoles { get; init; } = Array.Empty(); - } - internal class Handler(IUserService _userService) : ICommandHandler - { - public async Task HandleAsync(Command request, CancellationToken cancellationToken = default) => - await _userService.AssignRolesAsync(request.UserId, request.UserRoles, cancellationToken); - } - internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpoints) - { - return endpoints.MapPost("/{id:guid}/roles", async (Command command, - HttpContext context, - string id, - ICommandDispatcher dispatcher, - CancellationToken cancellationToken) => - { - var result = await dispatcher.SendAsync(command, cancellationToken); - return Results.Ok(result); - }) - .WithName(nameof(AssignUserRoles)) - .WithSummary("assign roles") - .WithDescription("assign roles"); - } -} diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/IdentityConstants.cs b/src/framework/Modules/Identity/Identity.Infrastructure/IdentityConstants.cs deleted file mode 100644 index 4542975e2..000000000 --- a/src/framework/Modules/Identity/Identity.Infrastructure/IdentityConstants.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace FSH.Framework.Identity.Infrastructure; -public static class IdentityConstants -{ - public const string SchemaName = "identity"; -} diff --git a/src/framework/Modules/Tenant/TenantModule.cs b/src/framework/Modules/Tenant/TenantModule.cs index 99d9f9941..3d1f0210c 100644 --- a/src/framework/Modules/Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/TenantModule.cs @@ -1,31 +1,152 @@ using Asp.Versioning; +using Finbuckle.MultiTenant; +using Finbuckle.MultiTenant.Abstractions; +using Finbuckle.MultiTenant.Stores.DistributedCacheStore; +using FSH.Framework.Core.Persistence; using FSH.Framework.Infrastructure.Messaging.CQRS; -using FSH.Framework.Infrastructure.Modules; +using FSH.Framework.Infrastructure.Persistence; +using FSH.Framework.Infrastructure.Persistence.Services; +using FSH.Framework.Shared.Constants; +using FSH.Framework.Shared.Multitenancy; +using FSH.Framework.Tenant.Data; using FSH.Framework.Tenant.Features.v1.ActivateTenant; using FSH.Framework.Tenant.Features.v1.CreateTenant; using FSH.Framework.Tenant.Features.v1.DisableTenant; using FSH.Framework.Tenant.Features.v1.GetTenantById; using FSH.Framework.Tenant.Features.v1.GetTenants; using FSH.Framework.Tenant.Features.v1.UpgradeTenant; +using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Configuration; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Serilog; using System.Reflection; namespace FSH.Framework.Tenant; -public class TenantModule : IModule +public static class TenantModule { - public IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config) + public static IServiceCollection RegisterTenantModuleServices(this IServiceCollection services) { + ArgumentNullException.ThrowIfNull(services); services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); + services.AddTransient(); + services.BindDbContext(); + services + .AddMultiTenant(config => + { + // to save database calls to resolve tenant + // this was happening for every request earlier, leading to ineffeciency + config.Events.OnTenantResolveCompleted = async (context) => + { + if (context.MultiTenantContext.StoreInfo is null) return; + if (context.MultiTenantContext.StoreInfo.StoreType != typeof(DistributedCacheStore)) + { + var sp = ((HttpContext)context.Context!).RequestServices; + var distributedCacheStore = sp + .GetService>>()! + .FirstOrDefault(s => s.GetType() == typeof(DistributedCacheStore)); - // other registrations + await distributedCacheStore!.TryAddAsync(context.MultiTenantContext.TenantInfo!); + } + await Task.FromResult(0); + }; + }) + .WithClaimStrategy(FshClaims.Tenant) + .WithHeaderStrategy(TenantConstants.Identifier) + .WithDelegateStrategy(async context => + { + if (context is not HttpContext httpContext) + return null; + if (!httpContext.Request.Query.TryGetValue("tenant", out var tenantIdentifier) || string.IsNullOrEmpty(tenantIdentifier)) + return null; + return await Task.FromResult(tenantIdentifier.ToString()); + }) + .WithDistributedCacheStore(TimeSpan.FromMinutes(60)) + .WithEFCoreStore(); + services.AddScoped(); return services; } + public static WebApplication UseTenantModule(this WebApplication app) + { + ArgumentNullException.ThrowIfNull(app); + app.UseMultiTenant(); + + // set up tenant store + var tenants = TenantStoreSetup(app); + + // set up tenant databases + app.SetupTenantDatabases(tenants); + + // register endpoints + app.MapTenantEndpoints(); + return app; + } + + private static IApplicationBuilder SetupTenantDatabases(this IApplicationBuilder app, IEnumerable tenants) + { + foreach (var tenant in tenants) + { + // create a scope for tenant + using var tenantScope = app.ApplicationServices.CreateScope(); + + //set current tenant so that the right connection string is used + tenantScope.ServiceProvider.GetRequiredService() + .MultiTenantContext = new MultiTenantContext() + { + TenantInfo = tenant + }; + + // using the scope, perform migrations / seeding + var initializers = tenantScope.ServiceProvider.GetServices(); + foreach (var initializer in initializers) + { + initializer.MigrateAsync(CancellationToken.None).Wait(); + initializer.SeedAsync(CancellationToken.None).Wait(); + } + } + return app; + } + + private static IEnumerable TenantStoreSetup(IApplicationBuilder app) + { + var scope = app.ApplicationServices.CreateScope(); + + // tenant master schema migration + var tenantDbContext = scope.ServiceProvider.GetRequiredService(); + if (tenantDbContext.Database.GetPendingMigrations().Any()) + { + tenantDbContext.Database.Migrate(); + Log.Information("applied database migrations for tenant module"); + } + + // default tenant seeding + if (tenantDbContext.TenantInfo.Find(TenantConstants.Root.Id) is null) + { + var rootTenant = new FshTenantInfo( + TenantConstants.Root.Id, + TenantConstants.Root.Name, + string.Empty, + TenantConstants.Root.EmailAddress); + + rootTenant.SetValidity(DateTime.UtcNow.AddYears(1)); + tenantDbContext.TenantInfo.Add(rootTenant); + tenantDbContext.SaveChanges(); + Log.Information("configured default tenant data"); + } + + // get all tenants from store + var tenantStore = scope.ServiceProvider.GetRequiredService>(); + var tenants = tenantStore.GetAllAsync().Result; + + //dispose scope + scope.Dispose(); + + return tenants; + } - public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) + public static IEndpointRouteBuilder MapTenantEndpoints(this IEndpointRouteBuilder endpoints) { var apiVersionSet = endpoints.NewApiVersionSet() .HasApiVersion(new ApiVersion(1)) From 779c394c358194d6eec16b851f0443bb397fa074 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Sun, 13 Apr 2025 00:44:20 +0530 Subject: [PATCH 27/54] cleanup --- .../ExecutionContext}/ICurrentUserInitializer.cs | 2 +- .../Identity/Services/CurrentUserService.cs | 5 ++--- src/framework/Identity/Services/IRoleService.cs | 7 +++---- .../ChangePassword/ChangePasswordEndpoint.cs | 2 +- .../ChangePassword/ChangePasswordValidator.cs | 1 + .../v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs | 2 +- .../Infrastructure/Jobs/FshJobActivator.cs | 7 +++---- src/framework/Infrastructure/Jobs/FshJobFilter.cs | 5 +++-- src/framework/Modules/Auditing/Auditing.csproj | 2 -- .../Shared/Multitenancy/MultiTenancyConstants.cs | 15 +++++++++++++++ 10 files changed, 30 insertions(+), 18 deletions(-) rename src/framework/{Identity/Services => Core/ExecutionContext}/ICurrentUserInitializer.cs (78%) create mode 100644 src/framework/Shared/Multitenancy/MultiTenancyConstants.cs diff --git a/src/framework/Identity/Services/ICurrentUserInitializer.cs b/src/framework/Core/ExecutionContext/ICurrentUserInitializer.cs similarity index 78% rename from src/framework/Identity/Services/ICurrentUserInitializer.cs rename to src/framework/Core/ExecutionContext/ICurrentUserInitializer.cs index 1824b7086..4773338fe 100644 --- a/src/framework/Identity/Services/ICurrentUserInitializer.cs +++ b/src/framework/Core/ExecutionContext/ICurrentUserInitializer.cs @@ -1,6 +1,6 @@ using System.Security.Claims; -namespace FSH.Framework.Identity.Core.Users; +namespace FSH.Framework.Core.ExecutionContext; public interface ICurrentUserInitializer { void SetCurrentUser(ClaimsPrincipal user); diff --git a/src/framework/Identity/Services/CurrentUserService.cs b/src/framework/Identity/Services/CurrentUserService.cs index 362eef171..bb3450df4 100644 --- a/src/framework/Identity/Services/CurrentUserService.cs +++ b/src/framework/Identity/Services/CurrentUserService.cs @@ -1,8 +1,7 @@ -using System.Security.Claims; -using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.ExecutionContext; -using FSH.Framework.Identity.Core.Users; using FSH.Framework.Shared.Extensions; +using System.Security.Claims; namespace FSH.Framework.Identity.Infrastructure.Users; public class CurrentUser : ICurrentUser, ICurrentUserInitializer diff --git a/src/framework/Identity/Services/IRoleService.cs b/src/framework/Identity/Services/IRoleService.cs index e0be11872..7fcb6fcac 100644 --- a/src/framework/Identity/Services/IRoleService.cs +++ b/src/framework/Identity/Services/IRoleService.cs @@ -1,5 +1,4 @@ -using FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; -using FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; +using System.Collections.ObjectModel; namespace FSH.Framework.Identity.Core.Roles; @@ -7,10 +6,10 @@ public interface IRoleService { Task> GetRolesAsync(); Task GetRoleAsync(string id); - Task CreateOrUpdateRoleAsync(UpsertRoleCommand request); + Task CreateOrUpdateRoleAsync(string roleId, string name, string description); Task DeleteRoleAsync(string id); Task GetWithPermissionsAsync(string id, CancellationToken cancellationToken); - Task UpdatePermissionsAsync(UpdatePermissionsCommand request); + Task UpdatePermissionsAsync(string roleId, Collection permissions); } diff --git a/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs b/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs index 5552a5cfc..61f6cecc6 100644 --- a/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs +++ b/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs @@ -32,7 +32,7 @@ internal static RouteHandlerBuilder MapChangePasswordEndpoint(this IEndpointRout return Results.BadRequest(); } - await userService.ChangePasswordAsync(command, userId); + await userService.ChangePasswordAsync(command.Password, command.NewPassword, command.ConfirmNewPassword, userId); return Results.Ok("password reset email sent"); }) .WithName(nameof(ChangePasswordEndpoint)) diff --git a/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs index 99ba3ad85..a409436ad 100644 --- a/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs +++ b/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs @@ -1,4 +1,5 @@ using FluentValidation; +using FSH.Framework.Identity.Contracts.v1.Users.ChangePassword; namespace FSH.Framework.Identity.Endpoints.v1.Users.ChangePassword; diff --git a/src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs b/src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs index c0800e332..5d70c9fd7 100644 --- a/src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs +++ b/src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; +using FSH.Framework.Identity.Core.Users; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Infrastructure/Jobs/FshJobActivator.cs b/src/framework/Infrastructure/Jobs/FshJobActivator.cs index dc0eb2fd8..516c2faf3 100644 --- a/src/framework/Infrastructure/Jobs/FshJobActivator.cs +++ b/src/framework/Infrastructure/Jobs/FshJobActivator.cs @@ -1,9 +1,8 @@ using Finbuckle.MultiTenant; using Finbuckle.MultiTenant.Abstractions; -using FSH.Framework.Core.Identity.Users.Abstractions; +using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Infrastructure.Constants; -using FSH.Framework.Infrastructure.Tenant; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Shared.Multitenancy; using Hangfire; using Hangfire.Server; using Microsoft.Extensions.DependencyInjection; @@ -35,7 +34,7 @@ public Scope(PerformContext context, IServiceScope scope) private void ReceiveParameters() { - var tenantInfo = _context.GetJobParameter(TenantConstants.Identifier); + var tenantInfo = _context.GetJobParameter(MultiTenancyConstants.Identifier); if (tenantInfo is not null) { _scope.ServiceProvider.GetRequiredService() diff --git a/src/framework/Infrastructure/Jobs/FshJobFilter.cs b/src/framework/Infrastructure/Jobs/FshJobFilter.cs index 54b83641b..bdf20459f 100644 --- a/src/framework/Infrastructure/Jobs/FshJobFilter.cs +++ b/src/framework/Infrastructure/Jobs/FshJobFilter.cs @@ -1,6 +1,7 @@ using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Infrastructure.Constants; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Shared.Extensions; +using FSH.Framework.Shared.Multitenancy; using Hangfire.Client; using Hangfire.Logging; using Microsoft.AspNetCore.Http; @@ -28,7 +29,7 @@ public void OnCreating(CreatingContext context) _ = httpContext ?? throw new InvalidOperationException("Can't create a TenantJob without HttpContext."); var tenantInfo = scope.ServiceProvider.GetRequiredService().MultiTenantContext.TenantInfo; - context.SetJobParameter(TenantConstants.Identifier, tenantInfo); + context.SetJobParameter(MultiTenancyConstants.Identifier, tenantInfo); string? userId = httpContext.User.GetUserId(); context.SetJobParameter(QueryStringKeys.UserId, userId); diff --git a/src/framework/Modules/Auditing/Auditing.csproj b/src/framework/Modules/Auditing/Auditing.csproj index d57e0e4d6..414a30df9 100644 --- a/src/framework/Modules/Auditing/Auditing.csproj +++ b/src/framework/Modules/Auditing/Auditing.csproj @@ -9,10 +9,8 @@ enable - - diff --git a/src/framework/Shared/Multitenancy/MultiTenancyConstants.cs b/src/framework/Shared/Multitenancy/MultiTenancyConstants.cs new file mode 100644 index 000000000..15dd06b89 --- /dev/null +++ b/src/framework/Shared/Multitenancy/MultiTenancyConstants.cs @@ -0,0 +1,15 @@ +namespace FSH.Framework.Shared.Multitenancy; +public static class MultiTenancyConstants +{ + public static class Root + { + public const string Id = "root"; + public const string Name = "Root"; + public const string EmailAddress = "admin@root.com"; + public const string DefaultProfilePicture = "assets/defaults/profile-picture.webp"; + } + + public const string DefaultPassword = "123Pa$$word!"; + + public const string Identifier = "tenant"; +} From 802c5d81caa6df9635cdbadd27c2011df36d4ad1 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Sun, 13 Apr 2025 01:07:30 +0530 Subject: [PATCH 28/54] more fixes --- src/framework/Core/Paging/IPageRequest.cs | 8 +- src/framework/Core/Paging/PaginationFilter.cs | 10 +- .../EntitiesByBaseFilterSpec.cs | 4 +- .../EntitiesByPaginationFilterSpec.cs | 4 +- .../SpecificationBuilderExtensions.cs | 150 +++++++++--------- .../Auth/CurrentUserMiddleware.cs | 2 +- .../Auth/Jwt/ConfigureJwtBearerOptions.cs | 7 +- 7 files changed, 89 insertions(+), 96 deletions(-) diff --git a/src/framework/Core/Paging/IPageRequest.cs b/src/framework/Core/Paging/IPageRequest.cs index 6d712599c..41ea56635 100644 --- a/src/framework/Core/Paging/IPageRequest.cs +++ b/src/framework/Core/Paging/IPageRequest.cs @@ -6,14 +6,14 @@ public interface IPageRequest { /// Page number (1-based). - int PageNumber { get; init; } + int PageNumber { get; set; } /// Number of items per page. - int PageSize { get; init; } + int PageSize { get; set; } /// Optional filter expression (raw or JSON). - string? Filters { get; init; } + string? Filters { get; set; } /// Optional sort order (e.g., "name asc", "created desc"). - string? SortOrder { get; init; } + string? SortOrder { get; set; } } diff --git a/src/framework/Core/Paging/PaginationFilter.cs b/src/framework/Core/Paging/PaginationFilter.cs index c3920145f..19b131d02 100644 --- a/src/framework/Core/Paging/PaginationFilter.cs +++ b/src/framework/Core/Paging/PaginationFilter.cs @@ -2,10 +2,10 @@ public class PaginationFilter : BaseFilter, IPageRequest { - public int PageNumber { get; init; } = 1; - public int PageSize { get; init; } = 10; - public IReadOnlyList? OrderBy { get; init; } + public int PageNumber { get; set; } = 1; + public int PageSize { get; set; } = 10; + public string[] OrderBy { get; set; } - public string? Filters { get; init; } - public string? SortOrder { get; init; } + public string? Filters { get; set; } + public string? SortOrder { get; set; } } diff --git a/src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs b/src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs index 643bcb675..4b14bd2bf 100644 --- a/src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs +++ b/src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs @@ -3,13 +3,13 @@ namespace FSH.Framework.Core.Specifications; -public class EntitiesByBaseFilterSpec : Specification +public class EntitiesByBaseFilterSpec : Specification where T : class { public EntitiesByBaseFilterSpec(BaseFilter filter) => Query.SearchBy(filter); } -public class EntitiesByBaseFilterSpec : Specification +public class EntitiesByBaseFilterSpec : Specification where T : class { public EntitiesByBaseFilterSpec(BaseFilter filter) => Query.SearchBy(filter); diff --git a/src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs b/src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs index abdf49eeb..a2ff6ba52 100644 --- a/src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs +++ b/src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs @@ -2,14 +2,14 @@ namespace FSH.Framework.Core.Specifications; -public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec +public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec where T : class { public EntitiesByPaginationFilterSpec(PaginationFilter filter) : base(filter) => Query.PaginateBy(filter); } -public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec +public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec where T : class { public EntitiesByPaginationFilterSpec(PaginationFilter filter) : base(filter) => diff --git a/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs b/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs index a16362f99..84fafe24d 100644 --- a/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs +++ b/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs @@ -7,53 +7,50 @@ namespace FSH.Framework.Core.Specifications; -// See https://github.com/ardalis/Specification/issues/53 public static class SpecificationBuilderExtensions { - public static ISpecificationBuilder SearchBy(this ISpecificationBuilder query, BaseFilter filter) => + public static ISpecificationBuilder SearchBy(this ISpecificationBuilder query, BaseFilter filter) where T : class => query .SearchByKeyword(filter.Keyword) .AdvancedSearch(filter.AdvancedSearch) .AdvancedFilter(filter.AdvancedFilter); - public static ISpecificationBuilder PaginateBy( - this ISpecificationBuilder query, - PaginationFilter filter) + public static ISpecificationBuilder PaginateBy(this ISpecificationBuilder query, PaginationFilter filter) { - var pageNumber = filter.PageNumber <= 0 ? 1 : filter.PageNumber; - var pageSize = filter.PageSize <= 0 ? 10 : filter.PageSize; - - if (pageNumber > 1) + if (filter.PageNumber <= 0) { - query = query.Skip((pageNumber - 1) * pageSize); + filter.PageNumber = 1; } - query = query.Take(pageSize); + if (filter.PageSize <= 0) + { + filter.PageSize = 10; + } - if (filter.OrderBy is { Count: > 0 }) + if (filter.PageNumber > 1) { - query = query.OrderBy(filter.OrderBy.ToArray()); + query = query.Skip((filter.PageNumber - 1) * filter.PageSize); } - return query; + return query + .Take(filter.PageSize) + .OrderBy(filter.OrderBy); } - - - public static IOrderedSpecificationBuilder SearchByKeyword( + public static ISpecificationBuilder SearchByKeyword( this ISpecificationBuilder specificationBuilder, - string? keyword) => + string? keyword) where T : class => specificationBuilder.AdvancedSearch(new Search { Keyword = keyword }); - public static IOrderedSpecificationBuilder AdvancedSearch( + public static ISpecificationBuilder AdvancedSearch( this ISpecificationBuilder specificationBuilder, - Search? search) + Search? search) where T : class { if (!string.IsNullOrEmpty(search?.Keyword)) { if (search.Fields?.Any() is true) { - // search seleted fields (can contain deeper nested fields) + // search selected fields (can contain deeper nested fields) foreach (string field in search.Fields) { var paramExpr = Expression.Parameter(typeof(T)); @@ -78,7 +75,7 @@ public static IOrderedSpecificationBuilder AdvancedSearch( } } - return new OrderedSpecificationBuilder(specificationBuilder.Specification); + return specificationBuilder; } private static void AddSearchPropertyByKeyword( @@ -86,19 +83,19 @@ private static void AddSearchPropertyByKeyword( Expression propertyExpr, ParameterExpression paramExpr, string keyword, - FilterOperator operatorSearch = FilterOperator.Contains) + FilterOperator operatorSearch = FilterOperator.Contains) where T : class { if (propertyExpr is not MemberExpression memberExpr || memberExpr.Member is not PropertyInfo property) { throw new ArgumentException("propertyExpr must be a property expression.", nameof(propertyExpr)); } - var searchTerm = operatorSearch switch + string searchTerm = operatorSearch switch { FilterOperator.StartsWith => $"{keyword.ToLower()}%", FilterOperator.EndsWith => $"%{keyword.ToLower()}", FilterOperator.Contains => $"%{keyword.ToLower()}%", - _ => throw new CustomException($"Unsupported filter operator: {operatorSearch}") + _ => throw new ArgumentException("operatorSearch is not valid.", nameof(operatorSearch)) }; // Generate lambda [ x => x.Property ] for string properties @@ -114,13 +111,12 @@ private static void AddSearchPropertyByKeyword( var toLowerMethod = typeof(string).GetMethod("ToLower", Type.EmptyTypes); Expression callToLowerMethod = Expression.Call(selectorExpr, toLowerMethod!); - var selector = Expression.Lambda>(callToLowerMethod, paramExpr); + var selector = Expression.Lambda>(callToLowerMethod, paramExpr); - ((List>)specificationBuilder.Specification.SearchCriterias) - .Add(new SearchExpressionInfo(selector, searchTerm, 1)); + specificationBuilder.Search(selector, searchTerm, 1); } - public static IOrderedSpecificationBuilder AdvancedFilter( + public static ISpecificationBuilder AdvancedFilter( this ISpecificationBuilder specificationBuilder, Filter? filter) { @@ -128,28 +124,28 @@ public static IOrderedSpecificationBuilder AdvancedFilter( { var parameter = Expression.Parameter(typeof(T)); - Expression binaryExpresioFilter; + Expression binaryExpressionFilter; - if (!string.IsNullOrEmpty(filter.Logic)) + if (filter.Logic.HasValue) { if (filter.Filters is null) throw new CustomException("The Filters attribute is required when declaring a logic"); - binaryExpresioFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); + binaryExpressionFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); } else { var filterValid = GetValidFilter(filter); - binaryExpresioFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!, filterValid.Value, parameter); + binaryExpressionFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!.Value, filterValid.Value, parameter); } - ((List>)specificationBuilder.Specification.WhereExpressions) - .Add(new WhereExpressionInfo(Expression.Lambda>(binaryExpresioFilter, parameter))); + var expr = Expression.Lambda>(binaryExpressionFilter, parameter); + specificationBuilder.Where(expr); } - return new OrderedSpecificationBuilder(specificationBuilder.Specification); + return specificationBuilder; } private static Expression CreateFilterExpression( - string logic, + FilterLogic? logic, IEnumerable filters, ParameterExpression parameter) { @@ -157,20 +153,20 @@ private static Expression CreateFilterExpression( foreach (var filter in filters) { - Expression bExpresionFilter; + Expression bExpressionFilter; - if (!string.IsNullOrEmpty(filter.Logic)) + if (filter.Logic.HasValue) { if (filter.Filters is null) throw new CustomException("The Filters attribute is required when declaring a logic"); - bExpresionFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); + bExpressionFilter = CreateFilterExpression(filter.Logic, filter.Filters, parameter); } else { var filterValid = GetValidFilter(filter); - bExpresionFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!, filterValid.Value, parameter); + bExpressionFilter = CreateFilterExpression(filterValid.Field!, filterValid.Operator!.Value, filterValid.Value, parameter); } - filterExpression = filterExpression is null ? bExpresionFilter : CombineFilter(logic, filterExpression, bExpresionFilter); + filterExpression = filterExpression is null ? bExpressionFilter : CombineFilter(logic, filterExpression, bExpressionFilter); } return filterExpression; @@ -178,13 +174,13 @@ private static Expression CreateFilterExpression( private static Expression CreateFilterExpression( string field, - string filterOperator, + FilterOperator filterOperator, object? value, ParameterExpression parameter) { - var propertyExpresion = GetPropertyExpression(field, parameter); - var valueExpresion = GeValuetExpression(field, value, propertyExpresion.Type); - return CreateFilterExpression(propertyExpresion, valueExpresion, filterOperator); + var propertyExpression = GetPropertyExpression(field, parameter); + var valueExpression = GeValueExpression(field, value, propertyExpression.Type); + return CreateFilterExpression(propertyExpression, valueExpression, filterOperator); } private static Expression CreateFilterExpression( @@ -194,8 +190,8 @@ private static Expression CreateFilterExpression( { if (memberExpression.Type == typeof(string)) { - constantExpression = Expression.Call(constantExpression, nameof(string.ToLower), null); - memberExpression = Expression.Call(memberExpression, nameof(string.ToLower), null); + constantExpression = Expression.Call(constantExpression, "ToLower", null); + memberExpression = Expression.Call(memberExpression, "ToLower", null); } return filterOperator switch @@ -206,28 +202,23 @@ private static Expression CreateFilterExpression( FilterOperator.Lte => Expression.LessThanOrEqual(memberExpression, constantExpression), FilterOperator.Gt => Expression.GreaterThan(memberExpression, constantExpression), FilterOperator.Gte => Expression.GreaterThanOrEqual(memberExpression, constantExpression), - FilterOperator.Contains => Expression.Call(memberExpression, nameof(string.Contains), null, constantExpression), - FilterOperator.StartsWith => Expression.Call(memberExpression, nameof(string.StartsWith), null, constantExpression), - FilterOperator.EndsWith => Expression.Call(memberExpression, nameof(string.EndsWith), null, constantExpression), - _ => throw new CustomException("Filter operator is not valid.") + FilterOperator.Contains => Expression.Call(memberExpression, "Contains", null, constantExpression), + FilterOperator.StartsWith => Expression.Call(memberExpression, "StartsWith", null, constantExpression), + FilterOperator.EndsWith => Expression.Call(memberExpression, "EndsWith", null, constantExpression), + _ => throw new CustomException("Filter Operator is not valid."), }; } - - private static Expression CombineFilter( - FilterLogic logic, - Expression left, - Expression right) - { - return logic switch + private static BinaryExpression CombineFilter( + FilterLogic? filterOperator, + Expression bExpressionBase, + Expression bExpression) => filterOperator switch { - FilterLogic.And => Expression.And(left, right), - FilterLogic.Or => Expression.Or(left, right), - FilterLogic.Xor => Expression.ExclusiveOr(left, right), - _ => throw new ArgumentOutOfRangeException(nameof(logic), "Invalid filter logic.") + FilterLogic.And => Expression.And(bExpressionBase, bExpression), + FilterLogic.Or => Expression.Or(bExpressionBase, bExpression), + FilterLogic.Xor => Expression.ExclusiveOr(bExpressionBase, bExpression), + _ => throw new ArgumentException("FilterLogic is not valid."), }; - } - private static MemberExpression GetPropertyExpression( string propertyName, @@ -245,7 +236,7 @@ private static MemberExpression GetPropertyExpression( private static string GetStringFromJsonElement(object value) => ((JsonElement)value).GetString()!; - private static ConstantExpression GeValuetExpression( + private static ConstantExpression GeValueExpression( string field, object? value, Type propertyType) @@ -305,20 +296,17 @@ private static ConstantExpression GeValuetExpression( private static Filter GetValidFilter(Filter filter) { - if (string.IsNullOrWhiteSpace(filter.Field)) - throw new CustomException("The 'Field' property is required when declaring a filter."); - - // Optional: check if Operator is defined in the enum (defensive) - if (!Enum.IsDefined(typeof(FilterOperator), filter.Operator!)) - throw new CustomException($"Invalid filter operator: {filter.Operator}"); - + if (string.IsNullOrEmpty(filter.Field)) throw new CustomException("The field attribute is required when declaring a filter"); + if (string.IsNullOrEmpty(filter.Operator.Value.ToString())) throw new CustomException("The Operator attribute is required when declaring a filter"); return filter; } - public static IOrderedSpecificationBuilder OrderBy( + public static ISpecificationBuilder OrderBy( this ISpecificationBuilder specificationBuilder, string[]? orderByFields) { + IOrderedSpecificationBuilder orderedBuilder = null!; + if (orderByFields is not null) { foreach (var field in ParseOrderBy(orderByFields)) @@ -335,12 +323,18 @@ public static IOrderedSpecificationBuilder OrderBy( Expression.Convert(propertyExpr, typeof(object)), paramExpr); - ((List>)specificationBuilder.Specification.OrderExpressions) - .Add(new OrderExpressionInfo(keySelector, field.Value)); + orderedBuilder = field.Value switch + { + OrderTypeEnum.OrderBy => specificationBuilder.OrderBy(keySelector), + OrderTypeEnum.OrderByDescending => specificationBuilder.OrderByDescending(keySelector), + OrderTypeEnum.ThenBy => orderedBuilder.ThenBy(keySelector), + OrderTypeEnum.ThenByDescending => orderedBuilder.ThenByDescending(keySelector), + _ => throw new CustomException("OrderTypeEnum is not valid."), + }; } } - return new OrderedSpecificationBuilder(specificationBuilder.Specification); + return specificationBuilder; } private static Dictionary ParseOrderBy(string[] orderByFields) => @@ -357,4 +351,4 @@ private static Dictionary ParseOrderBy(string[] orderByFi return new KeyValuePair(field, orderBy); })); -} +} \ No newline at end of file diff --git a/src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs b/src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs index b4deef087..09fd012aa 100644 --- a/src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs +++ b/src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; +using FSH.Framework.Core.ExecutionContext; using Microsoft.AspNetCore.Http; namespace FSH.Framework.Infrastructure.Auth; diff --git a/src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs b/src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs index 8e495d207..3ce9c9308 100644 --- a/src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs +++ b/src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs @@ -1,10 +1,9 @@ -using System.Security.Claims; -using System.Text; -using FSH.Framework.Core.Auth.Jwt; -using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.Exceptions; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; +using System.Security.Claims; +using System.Text; namespace FSH.Framework.Infrastructure.Auth.Jwt; public class ConfigureJwtBearerOptions : IConfigureNamedOptions From efc369440209ad4884ecf12e5bddc3cc0aba0ca0 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 16 Apr 2025 10:54:06 +0530 Subject: [PATCH 29/54] cleanup --- .../AssignUserRoles/AssignUserRolesCommand.cs | 2 +- .../Identity/Data/IdentityConfigurations.cs | 17 +++-- .../Options}/ConfigureJwtBearerOptions.cs | 6 +- src/framework/Identity/Options/JwtOptions.cs | 2 +- .../Identity/Services/IRoleService.cs | 6 +- .../Identity/Services/IUserService.cs | 2 +- .../Identity/Services/UserService.cs | 70 ++++++++++--------- .../Roles/DeleteRole}/DeleteRoleEndpoint.cs | 6 +- .../v1/Roles/GetRole}/GetRoleEndpoint.cs | 4 +- .../GetRolePermissionsEndpoint.cs | 4 +- .../v1/Roles/GetRoles}/GetRolesEndpoint.cs | 4 +- .../UpdateRolePermissionsEndpoint.cs | 8 +-- .../UpsertRole}/CreateOrUpdateRoleEndpoint.cs | 10 +-- .../v1/Users/DeleteUser/DeleteUserEndpoint.cs | 4 +- .../ForgotPassword/ForgotPasswordEndpoint.cs | 8 +-- .../Auth/Jwt/JwtAuthConstants.cs | 6 -- .../Identity/Roles/Endpoints/Extensions.cs | 18 ----- 17 files changed, 80 insertions(+), 97 deletions(-) rename src/framework/{Infrastructure/Auth/Jwt => Identity/Options}/ConfigureJwtBearerOptions.cs (93%) rename src/framework/{Infrastructure/Identity/Roles/Endpoints => Identity/v1/Roles/DeleteRole}/DeleteRoleEndpoint.cs (80%) rename src/framework/{Infrastructure/Identity/Roles/Endpoints => Identity/v1/Roles/GetRole}/GetRoleEndpoint.cs (88%) rename src/framework/{Infrastructure/Identity/Roles/Endpoints => Identity/v1/Roles/GetRoleWithPermissions}/GetRolePermissionsEndpoint.cs (89%) rename src/framework/{Infrastructure/Identity/Roles/Endpoints => Identity/v1/Roles/GetRoles}/GetRolesEndpoint.cs (88%) rename src/framework/{Infrastructure/Identity/Roles/Endpoints => Identity/v1/Roles/UpdateRolePermissions}/UpdateRolePermissionsEndpoint.cs (84%) rename src/framework/{Infrastructure/Identity/Roles/Endpoints => Identity/v1/Roles/UpsertRole}/CreateOrUpdateRoleEndpoint.cs (68%) delete mode 100644 src/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs delete mode 100644 src/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs diff --git a/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs b/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs index b6e4dbf73..cca339a32 100644 --- a/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs +++ b/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs @@ -5,5 +5,5 @@ namespace FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; public sealed class AssignUserRolesCommand : ICommand { public required string UserId { get; init; } - public IReadOnlyList UserRoles { get; init; } = Array.Empty(); + public List UserRoles { get; init; } = new(); } diff --git a/src/framework/Identity/Data/IdentityConfigurations.cs b/src/framework/Identity/Data/IdentityConfigurations.cs index 6116fb99f..752f3be6d 100644 --- a/src/framework/Identity/Data/IdentityConfigurations.cs +++ b/src/framework/Identity/Data/IdentityConfigurations.cs @@ -1,6 +1,9 @@ using Finbuckle.MultiTenant; +using FSH.Framework.Identity.Contracts; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Identity.v1.RoleClaims; +using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -11,7 +14,7 @@ public class ApplicationUserConfig : IEntityTypeConfiguration public void Configure(EntityTypeBuilder builder) { builder - .ToTable("Users", IdentityConstants.SchemaName) + .ToTable("Users", IdentityModuleConstants.SchemaName) .IsMultiTenant(); builder @@ -24,7 +27,7 @@ public class ApplicationRoleConfig : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) => builder - .ToTable("Roles", IdentityConstants.SchemaName) + .ToTable("Roles", IdentityModuleConstants.SchemaName) .IsMultiTenant() .AdjustUniqueIndexes(); } @@ -33,7 +36,7 @@ public class ApplicationRoleClaimConfig : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) => builder - .ToTable("RoleClaims", IdentityConstants.SchemaName) + .ToTable("RoleClaims", IdentityModuleConstants.SchemaName) .IsMultiTenant(); } @@ -41,7 +44,7 @@ public class IdentityUserRoleConfig : IEntityTypeConfiguration> builder) => builder - .ToTable("UserRoles", IdentityConstants.SchemaName) + .ToTable("UserRoles", IdentityModuleConstants.SchemaName) .IsMultiTenant(); } @@ -49,7 +52,7 @@ public class IdentityUserClaimConfig : IEntityTypeConfiguration> builder) => builder - .ToTable("UserClaims", IdentityConstants.SchemaName) + .ToTable("UserClaims", IdentityModuleConstants.SchemaName) .IsMultiTenant(); } @@ -57,7 +60,7 @@ public class IdentityUserLoginConfig : IEntityTypeConfiguration> builder) => builder - .ToTable("UserLogins", IdentityConstants.SchemaName) + .ToTable("UserLogins", IdentityModuleConstants.SchemaName) .IsMultiTenant(); } @@ -65,6 +68,6 @@ public class IdentityUserTokenConfig : IEntityTypeConfiguration> builder) => builder - .ToTable("UserTokens", IdentityConstants.SchemaName) + .ToTable("UserTokens", IdentityModuleConstants.SchemaName) .IsMultiTenant(); } diff --git a/src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs b/src/framework/Identity/Options/ConfigureJwtBearerOptions.cs similarity index 93% rename from src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs rename to src/framework/Identity/Options/ConfigureJwtBearerOptions.cs index 3ce9c9308..7381ed077 100644 --- a/src/framework/Infrastructure/Auth/Jwt/ConfigureJwtBearerOptions.cs +++ b/src/framework/Identity/Options/ConfigureJwtBearerOptions.cs @@ -5,7 +5,7 @@ using System.Security.Claims; using System.Text; -namespace FSH.Framework.Infrastructure.Auth.Jwt; +namespace FSH.Framework.Identity.Options; public class ConfigureJwtBearerOptions : IConfigureNamedOptions { private readonly JwtOptions _options; @@ -35,10 +35,10 @@ public void Configure(string? name, JwtBearerOptions options) { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), - ValidIssuer = JwtAuthConstants.Issuer, + ValidIssuer = _options.Issuer, ValidateIssuer = true, ValidateLifetime = true, - ValidAudience = JwtAuthConstants.Audience, + ValidAudience = _options.Audience, ValidateAudience = true, RoleClaimType = ClaimTypes.Role, ClockSkew = TimeSpan.Zero diff --git a/src/framework/Identity/Options/JwtOptions.cs b/src/framework/Identity/Options/JwtOptions.cs index fe56d9e13..ea99b4959 100644 --- a/src/framework/Identity/Options/JwtOptions.cs +++ b/src/framework/Identity/Options/JwtOptions.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace FSH.Framework.Identity.Infrastructure; +namespace FSH.Framework.Identity.Options; public class JwtOptions : IValidatableObject { public string Key { get; set; } = string.Empty; diff --git a/src/framework/Identity/Services/IRoleService.cs b/src/framework/Identity/Services/IRoleService.cs index 7fcb6fcac..d979300f3 100644 --- a/src/framework/Identity/Services/IRoleService.cs +++ b/src/framework/Identity/Services/IRoleService.cs @@ -1,6 +1,4 @@ -using System.Collections.ObjectModel; - -namespace FSH.Framework.Identity.Core.Roles; +namespace FSH.Framework.Identity.Core.Roles; public interface IRoleService { @@ -10,6 +8,6 @@ public interface IRoleService Task DeleteRoleAsync(string id); Task GetWithPermissionsAsync(string id, CancellationToken cancellationToken); - Task UpdatePermissionsAsync(string roleId, Collection permissions); + Task UpdatePermissionsAsync(string roleId, List permissions); } diff --git a/src/framework/Identity/Services/IUserService.cs b/src/framework/Identity/Services/IUserService.cs index 2ec971c1c..210eb7cf2 100644 --- a/src/framework/Identity/Services/IUserService.cs +++ b/src/framework/Identity/Services/IUserService.cs @@ -14,7 +14,7 @@ public interface IUserService Task ToggleStatusAsync(bool activateUser, string userId, CancellationToken cancellationToken); Task GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal); Task RegisterAsync(string firstName, string lastName, string email, string userName, string password, string confirmPassword, string phoneNumber, string origin, CancellationToken cancellationToken); - Task UpdateAsync(string userId, string firstName, string lastName, string email, FileUploadRequest image, bool deleteCurrentImage); + Task UpdateAsync(string userId, string firstName, string lastName, string phoneNumber, FileUploadRequest image, bool deleteCurrentImage); Task DeleteAsync(string userId); Task ConfirmEmailAsync(string userId, string code, string tenant, CancellationToken cancellationToken); Task ConfirmPhoneNumberAsync(string userId, string code); diff --git a/src/framework/Identity/Services/UserService.cs b/src/framework/Identity/Services/UserService.cs index 563cd2568..458a4177e 100644 --- a/src/framework/Identity/Services/UserService.cs +++ b/src/framework/Identity/Services/UserService.cs @@ -1,20 +1,24 @@ -using System.Collections.ObjectModel; -using System.Security.Claims; -using System.Text; +using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Caching; using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.Identity.Users.Dtos; using FSH.Framework.Core.Jobs; using FSH.Framework.Core.Mail; using FSH.Framework.Core.Storage; +using FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; using FSH.Framework.Identity.Core.Roles; using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Infrastructure.Data; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Infrastructure.Constants; using FSH.Framework.Shared.Constants; +using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.WebUtilities; using Microsoft.EntityFrameworkCore; +using System.Collections.ObjectModel; +using System.Security.Claims; +using System.Text; namespace FSH.Framework.Infrastructure.Identity.Users.Services; @@ -79,7 +83,7 @@ public async Task ExistsWithPhoneNumberAsync(string phoneNumber, string? e return await userManager.Users.FirstOrDefaultAsync(x => x.PhoneNumber == phoneNumber) is FshUser user && user.Id != exceptId; } - public async Task GetAsync(string userId, CancellationToken cancellationToken) + public async Task GetAsync(string userId, CancellationToken cancellationToken) { var user = await userManager.Users .AsNoTracking() @@ -88,7 +92,7 @@ public async Task GetAsync(string userId, CancellationToken cance _ = user ?? throw new NotFoundException("user not found"); - return new UserDetailDto + return new UserDto { Id = user.Id, Email = user.Email, @@ -103,13 +107,13 @@ public async Task GetAsync(string userId, CancellationToken cance public Task GetCountAsync(CancellationToken cancellationToken) => userManager.Users.AsNoTracking().CountAsync(cancellationToken); - public async Task> GetListAsync(CancellationToken cancellationToken) + public async Task> GetListAsync(CancellationToken cancellationToken) { var users = await userManager.Users.AsNoTracking().ToListAsync(cancellationToken); - var result = new List(users.Count); + var result = new List(users.Count); foreach (var user in users) { - result.Add(new UserDetailDto + result.Add(new UserDto { Id = user.Id, Email = user.Email, @@ -129,23 +133,25 @@ public Task GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal) throw new NotImplementedException(); } - public async Task RegisterAsync(RegisterUserCommand request, string origin, CancellationToken cancellationToken) + public async Task RegisterAsync(string firstName, string lastName, string email, string userName, string password, string confirmPassword, string phoneNumber, string origin, CancellationToken cancellationToken) { + if (password != confirmPassword) throw new CustomException("password mismatch."); + // create user entity var user = new FshUser { - Email = request.Email, - FirstName = request.FirstName, - LastName = request.LastName, - UserName = request.UserName, - PhoneNumber = request.PhoneNumber, + Email = email, + FirstName = firstName, + LastName = lastName, + UserName = userName, + PhoneNumber = phoneNumber, IsActive = true, EmailConfirmed = false, PhoneNumberConfirmed = false, }; // register user - var result = await userManager.CreateAsync(user, request.Password); + var result = await userManager.CreateAsync(user, password); if (!result.Succeeded) { var errors = result.Errors.Select(error => error.Description).ToList(); @@ -163,15 +169,15 @@ public async Task RegisterAsync(RegisterUserCommand reques new Collection { user.Email }, "Confirm Registration", emailVerificationUri); - jobService.Enqueue("email", () => mailService.SendAsync(mailRequest, CancellationToken.None)); + jobService.Enqueue("email", () => mailService.SendAsync(mailRequest, cancellationToken)); } - return new RegisterUserResponse(user.Id); + return user.Id; } - public async Task ToggleStatusAsync(ToggleUserStatusCommand request, CancellationToken cancellationToken) + public async Task ToggleStatusAsync(bool activateUser, string userId, CancellationToken cancellationToken) { - var user = await userManager.Users.Where(u => u.Id == request.UserId).FirstOrDefaultAsync(cancellationToken); + var user = await userManager.Users.Where(u => u.Id == userId).FirstOrDefaultAsync(cancellationToken); _ = user ?? throw new NotFoundException("User Not Found."); @@ -181,34 +187,34 @@ public async Task ToggleStatusAsync(ToggleUserStatusCommand request, Cancellatio throw new CustomException("Administrators Profile's Status cannot be toggled"); } - user.IsActive = request.ActivateUser; + user.IsActive = activateUser; await userManager.UpdateAsync(user); } - public async Task UpdateAsync(UpdateUserCommand request, string userId) + public async Task UpdateAsync(string userId, string firstName, string lastName, string phoneNumber, FileUploadRequest image, bool deleteCurrentImage) { var user = await userManager.FindByIdAsync(userId); _ = user ?? throw new NotFoundException("user not found"); Uri imageUri = user.ImageUrl ?? null!; - if (request.Image != null || request.DeleteCurrentImage) + if (image.Data != null || deleteCurrentImage) { - user.ImageUrl = await storageService.UploadAsync(request.Image, FileType.Image); - if (request.DeleteCurrentImage && imageUri != null) + var imageString = await storageService.UploadAsync(image, FileType.Image); + user.ImageUrl = new Uri(imageString); + if (deleteCurrentImage && imageUri != null) { await storageService.RemoveAsync(imageUri.ToString()); } } - user.FirstName = request.FirstName; - user.LastName = request.LastName; - user.PhoneNumber = request.PhoneNumber; - string? phoneNumber = await userManager.GetPhoneNumberAsync(user); - if (request.PhoneNumber != phoneNumber) + user.FirstName = firstName; + user.LastName = lastName; + string? currentPhoneNumber = await userManager.GetPhoneNumberAsync(user); + if (phoneNumber != currentPhoneNumber) { - await userManager.SetPhoneNumberAsync(user, request.PhoneNumber); + await userManager.SetPhoneNumberAsync(user, phoneNumber); } var result = await userManager.UpdateAsync(user); @@ -252,7 +258,7 @@ private async Task GetEmailVerificationUriAsync(FshUser user, string ori return verificationUri; } - public async Task AssignRolesAsync(string userId, AssignUserRoleCommand request, CancellationToken cancellationToken) + public async Task AssignRolesAsync(string userId, AssignUserRolesCommand request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); diff --git a/src/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs b/src/framework/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs similarity index 80% rename from src/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs rename to src/framework/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs index 106ea082b..7ce3a5cf7 100644 --- a/src/framework/Infrastructure/Identity/Roles/Endpoints/DeleteRoleEndpoint.cs +++ b/src/framework/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs @@ -1,10 +1,10 @@ -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Infrastructure.Identity.Roles.Endpoints; +namespace FSH.Framework.Identity.v1.Roles.DeleteRole; public static class DeleteRoleEndpoint { diff --git a/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs b/src/framework/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs similarity index 88% rename from src/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs rename to src/framework/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs index 6064a3386..a62be69fb 100644 --- a/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRoleEndpoint.cs +++ b/src/framework/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs b/src/framework/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs similarity index 89% rename from src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs rename to src/framework/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs index 42eb89426..be97ef606 100644 --- a/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolePermissionsEndpoint.cs +++ b/src/framework/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs b/src/framework/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs similarity index 88% rename from src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs rename to src/framework/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs index df3b91cff..4e5143d43 100644 --- a/src/framework/Infrastructure/Identity/Roles/Endpoints/GetRolesEndpoint.cs +++ b/src/framework/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs b/src/framework/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs similarity index 84% rename from src/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs rename to src/framework/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs index 71cb44c61..dd7d8ccf8 100644 --- a/src/framework/Infrastructure/Identity/Roles/Endpoints/UpdateRolePermissionsEndpoint.cs +++ b/src/framework/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs @@ -1,7 +1,7 @@ using FluentValidation; -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Core.Identity.Roles.Features.UpdatePermissions; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -19,7 +19,7 @@ public static RouteHandlerBuilder MapUpdateRolePermissionsEndpoint(this IEndpoin [FromServices] IValidator validator) => { if (id != request.RoleId) return Results.BadRequest(); - var response = await roleService.UpdatePermissionsAsync(request); + var response = await roleService.UpdatePermissionsAsync(request.RoleId, request.Permissions); return Results.Ok(response); }) .WithName(nameof(UpdateRolePermissionsEndpoint)) diff --git a/src/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs b/src/framework/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs similarity index 68% rename from src/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs rename to src/framework/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs index 86234da7e..bbac696cb 100644 --- a/src/framework/Infrastructure/Identity/Roles/Endpoints/CreateOrUpdateRoleEndpoint.cs +++ b/src/framework/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Identity.Roles; -using FSH.Framework.Core.Identity.Roles.Features.CreateOrUpdateRole; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -11,9 +11,9 @@ public static class CreateOrUpdateRoleEndpoint { public static RouteHandlerBuilder MapCreateOrUpdateRoleEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/", async (CreateOrUpdateRoleCommand request, IRoleService roleService) => + return endpoints.MapPost("/", async (UpsertRoleCommand request, IRoleService roleService) => { - return await roleService.CreateOrUpdateRoleAsync(request); + return await roleService.CreateOrUpdateRoleAsync(request.Id, request.Name, request.Description); }) .WithName(nameof(CreateOrUpdateRoleEndpoint)) .WithSummary("Create or update a role") diff --git a/src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs b/src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs index 6969b4e12..13833d2e7 100644 --- a/src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs +++ b/src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs index 9483571e7..3b5036d99 100644 --- a/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs +++ b/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs @@ -1,9 +1,9 @@ using FluentValidation; using FluentValidation.Results; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.ForgotPassword; using FSH.Framework.Core.Origin; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Endpoints.v1.Users.ForgotPassword; +using FSH.Framework.Shared.Constants; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -33,7 +33,7 @@ internal static RouteHandlerBuilder MapForgotPasswordEndpoint(this IEndpointRout return Results.BadRequest("Origin URL is not configured."); } - await userService.ForgotPasswordAsync(command, origin.OriginUrl.ToString(), cancellationToken); + await userService.ForgotPasswordAsync(command.Email, origin.OriginUrl.ToString(), cancellationToken); return Results.Ok("Password reset email sent."); }) .WithName(nameof(ForgotPasswordEndpoint)) diff --git a/src/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs b/src/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs deleted file mode 100644 index b766fdf80..000000000 --- a/src/framework/Infrastructure/Auth/Jwt/JwtAuthConstants.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FSH.Framework.Infrastructure.Auth.Jwt; -internal static class JwtAuthConstants -{ - public const string Issuer = "https://fullstackhero.net"; - public const string Audience = "fullstackhero"; -} diff --git a/src/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs b/src/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs deleted file mode 100644 index b899bb362..000000000 --- a/src/framework/Infrastructure/Identity/Roles/Endpoints/Extensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Routing; - -namespace FSH.Framework.Infrastructure.Identity.Roles.Endpoints; - -internal static class Extensions -{ - public static IEndpointRouteBuilder MapRoleEndpoints(this IEndpointRouteBuilder app) - { - app.MapGetRoleEndpoint(); - app.MapGetRolesEndpoint(); - app.MapDeleteRoleEndpoint(); - app.MapCreateOrUpdateRoleEndpoint(); - app.MapGetRolePermissionsEndpoint(); - app.MapUpdateRolePermissionsEndpoint(); - return app; - } -} - From 0f201bc4859ab9777b83ea19956b27410c5a1ae2 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 16 Apr 2025 13:50:04 +0530 Subject: [PATCH 30/54] fix build errors --- .../Authorization}/CurrentUserMiddleware.cs | 0 .../Authorization}/Jwt/Extensions.cs | 4 +-- .../Identity/Data/IdentityDbInitializer.cs | 1 + src/framework/Identity/IdentityModule.cs | 4 +-- .../Identity/Services/IUserService.cs | 2 +- .../Identity/Services/TokenService.cs | 22 ++++++++----- .../Identity/Services/UserService.Password.cs | 24 +++++++------- .../Services/UserService.Permissions.cs | 2 ++ .../Identity/Services/UserService.cs | 9 ++---- .../Identity/v1/Roles/RoleService.cs | 24 +++++++------- .../v1/Users/GetUser/GetUserEndpoint.cs | 4 +-- .../GetUserPermissionsEndpoint.cs | 8 ++--- .../GetUserProfile/GetUserProfileEndpoint.cs | 6 ++-- .../v1/Users/GetUsers/GetUsersListEndpoint.cs | 4 +-- .../RegisterUser/RegisterUserEndpoint.cs | 16 +++++++--- .../ResetPassword/ResetPasswordEndpoint.cs | 14 +++++--- .../SelfRegisterUserEndpoint.cs | 18 ++++++++--- .../ToggleUserStatusEndpoint.cs | 6 ++-- .../UpdateUser/UpdateUserCommandValidator.cs | 2 +- .../v1/Users/UpdateUser/UpdateUserEndpoint.cs | 22 +++++++------ ...quiredPermissionAuthorizationExtensions.cs | 32 ------------------- .../Infrastructure/Cors/CorsOptions.cs | 5 ++- .../Exceptions/CustomExceptionHandler.cs | 4 +-- src/framework/Infrastructure/Extensions.cs | 2 -- .../Infrastructure/Infrastructure.csproj | 3 -- .../Infrastructure/Jobs/Extensions.cs | 4 +-- .../Infrastructure/Mail/SmtpMailService.cs | 19 ++++------- .../Auditing.Contracts/Dtos/TrailDto.cs | 28 +++++++++------- .../Data/Interceptors/AuditInterceptor.cs | 16 +++++----- .../Auditing/Mappings/TrailMappings.cs | 26 ++++++++------- 30 files changed, 161 insertions(+), 170 deletions(-) rename src/framework/{Infrastructure/Auth => Identity/Authorization}/CurrentUserMiddleware.cs (100%) rename src/framework/{Infrastructure/Auth => Identity/Authorization}/Jwt/Extensions.cs (92%) delete mode 100644 src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs diff --git a/src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs b/src/framework/Identity/Authorization/CurrentUserMiddleware.cs similarity index 100% rename from src/framework/Infrastructure/Auth/CurrentUserMiddleware.cs rename to src/framework/Identity/Authorization/CurrentUserMiddleware.cs diff --git a/src/framework/Infrastructure/Auth/Jwt/Extensions.cs b/src/framework/Identity/Authorization/Jwt/Extensions.cs similarity index 92% rename from src/framework/Infrastructure/Auth/Jwt/Extensions.cs rename to src/framework/Identity/Authorization/Jwt/Extensions.cs index 87a94d3ec..4beb33906 100644 --- a/src/framework/Infrastructure/Auth/Jwt/Extensions.cs +++ b/src/framework/Identity/Authorization/Jwt/Extensions.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Auth.Jwt; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Infrastructure.Authorization; +using FSH.Framework.Identity.Options; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; diff --git a/src/framework/Identity/Data/IdentityDbInitializer.cs b/src/framework/Identity/Data/IdentityDbInitializer.cs index 0f6478afa..7a395daee 100644 --- a/src/framework/Identity/Data/IdentityDbInitializer.cs +++ b/src/framework/Identity/Data/IdentityDbInitializer.cs @@ -3,6 +3,7 @@ using FSH.Framework.Core.Persistence; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Identity.v1.RoleClaims; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; diff --git a/src/framework/Identity/IdentityModule.cs b/src/framework/Identity/IdentityModule.cs index 86f917f8f..732f769ab 100644 --- a/src/framework/Identity/IdentityModule.cs +++ b/src/framework/Identity/IdentityModule.cs @@ -5,6 +5,7 @@ using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Identity.Core.Users; using FSH.Framework.Identity.Infrastructure.Data; +using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Tokens; using FSH.Framework.Identity.Infrastructure.Users; using FSH.Framework.Identity.v1.Tokens.TokenGeneration; @@ -14,13 +15,12 @@ using FSH.Framework.Infrastructure.Persistence; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace FSH.Framework.Identity; public static class IdentityModule { - public static IServiceCollection RegisterIdentityModule(this IServiceCollection services, IConfiguration config) + public static IServiceCollection RegisterIdentityModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); services.AddScoped(); diff --git a/src/framework/Identity/Services/IUserService.cs b/src/framework/Identity/Services/IUserService.cs index 210eb7cf2..38595f6d6 100644 --- a/src/framework/Identity/Services/IUserService.cs +++ b/src/framework/Identity/Services/IUserService.cs @@ -28,6 +28,6 @@ public interface IUserService Task?> GetPermissionsAsync(string userId, CancellationToken cancellationToken); Task ChangePasswordAsync(string password, string newPassword, string confirmNewPassword, string userId); - Task AssignRolesAsync(string userId, IReadOnlyList userRoles, CancellationToken cancellationToken); + Task AssignRolesAsync(string userId, List userRoles, CancellationToken cancellationToken); Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken); } diff --git a/src/framework/Identity/Services/TokenService.cs b/src/framework/Identity/Services/TokenService.cs index a9fc752b2..9084bb2aa 100644 --- a/src/framework/Identity/Services/TokenService.cs +++ b/src/framework/Identity/Services/TokenService.cs @@ -6,6 +6,7 @@ using FSH.Framework.Core.Messaging.Events; using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Identity.Infrastructure.Users; +using FSH.Framework.Identity.Options; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; @@ -109,15 +110,20 @@ private async Task GenerateTokensAndUpdateUser( await _userManager.UpdateAsync(user); - await _publisher.PublishAsync(new AuditPublishedEvent(new List + var trailDtos = new List { - new(Guid.NewGuid(), - DateTime.UtcNow, - new Guid(user.Id), - AuditOperation.Create, - "Token Generated", - "Identity") - })); + new() { + Id = Guid.NewGuid(), + DateTime = DateTimeOffset.UtcNow, + UserId = new Guid(user.Id), + Operation = AuditOperation.Create, + Description = "Token Generated", + EntityName = "Identity" + } + }; + + await _publisher.PublishAsync(new AuditPublishedEvent(trailDtos)); + return new TokenDto(token, user.RefreshToken, user.RefreshTokenExpiryTime); } diff --git a/src/framework/Identity/Services/UserService.Password.cs b/src/framework/Identity/Services/UserService.Password.cs index 6deb6db0c..4099318bd 100644 --- a/src/framework/Identity/Services/UserService.Password.cs +++ b/src/framework/Identity/Services/UserService.Password.cs @@ -1,17 +1,17 @@ -using System.Collections.ObjectModel; -using System.Text; -using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Mail; using Microsoft.AspNetCore.WebUtilities; +using System.Collections.ObjectModel; +using System.Text; namespace FSH.Framework.Infrastructure.Identity.Users.Services; internal sealed partial class UserService { - public async Task ForgotPasswordAsync(ForgotPasswordCommand request, string origin, CancellationToken cancellationToken) + public async Task ForgotPasswordAsync(string email, string origin, CancellationToken cancellationToken) { EnsureValidTenant(); - var user = await userManager.FindByEmailAsync(request.Email); + var user = await userManager.FindByEmailAsync(email); if (user == null) { throw new NotFoundException("user not found"); @@ -25,7 +25,7 @@ public async Task ForgotPasswordAsync(ForgotPasswordCommand request, string orig var token = await userManager.GeneratePasswordResetTokenAsync(user); token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token)); - var resetPasswordUri = $"{origin}/reset-password?token={token}&email={request.Email}"; + var resetPasswordUri = $"{origin}/reset-password?token={token}&email={email}"; var mailRequest = new MailRequest( new Collection { user.Email }, "Reset Password", @@ -34,18 +34,18 @@ public async Task ForgotPasswordAsync(ForgotPasswordCommand request, string orig jobService.Enqueue(() => mailService.SendAsync(mailRequest, CancellationToken.None)); } - public async Task ResetPasswordAsync(ResetPasswordCommand request, CancellationToken cancellationToken) + public async Task ResetPasswordAsync(string email, string password, string token, CancellationToken cancellationToken) { EnsureValidTenant(); - var user = await userManager.FindByEmailAsync(request.Email); + var user = await userManager.FindByEmailAsync(email); if (user == null) { throw new NotFoundException("user not found"); } - request.Token = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(request.Token)); - var result = await userManager.ResetPasswordAsync(user, request.Token, request.Password); + token = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(token)); + var result = await userManager.ResetPasswordAsync(user, token, password); if (!result.Succeeded) { @@ -54,13 +54,13 @@ public async Task ResetPasswordAsync(ResetPasswordCommand request, CancellationT } } - public async Task ChangePasswordAsync(ChangePasswordCommand request, string userId) + public async Task ChangePasswordAsync(string password, string newPassword, string confirmNewPassword, string userId) { var user = await userManager.FindByIdAsync(userId); _ = user ?? throw new NotFoundException("user not found"); - var result = await userManager.ChangePasswordAsync(user, request.Password, request.NewPassword); + var result = await userManager.ChangePasswordAsync(user, password, newPassword); if (!result.Succeeded) { diff --git a/src/framework/Identity/Services/UserService.Permissions.cs b/src/framework/Identity/Services/UserService.Permissions.cs index 2efd34cf6..9aa83426c 100644 --- a/src/framework/Identity/Services/UserService.Permissions.cs +++ b/src/framework/Identity/Services/UserService.Permissions.cs @@ -1,5 +1,7 @@ using FSH.Framework.Core.Caching; using FSH.Framework.Core.Exceptions; +using FSH.Framework.Shared.Constants; +using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Infrastructure.Identity.Users.Services; internal sealed partial class UserService diff --git a/src/framework/Identity/Services/UserService.cs b/src/framework/Identity/Services/UserService.cs index 458a4177e..54b7fa014 100644 --- a/src/framework/Identity/Services/UserService.cs +++ b/src/framework/Identity/Services/UserService.cs @@ -4,7 +4,6 @@ using FSH.Framework.Core.Jobs; using FSH.Framework.Core.Mail; using FSH.Framework.Core.Storage; -using FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; using FSH.Framework.Identity.Core.Roles; using FSH.Framework.Identity.Core.Users; using FSH.Framework.Identity.Infrastructure.Data; @@ -258,17 +257,15 @@ private async Task GetEmailVerificationUriAsync(FshUser user, string ori return verificationUri; } - public async Task AssignRolesAsync(string userId, AssignUserRolesCommand request, CancellationToken cancellationToken) + public async Task AssignRolesAsync(string userId, List userRoles, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(request); - var user = await userManager.Users.Where(u => u.Id == userId).FirstOrDefaultAsync(cancellationToken); _ = user ?? throw new NotFoundException("user not found"); // Check if the user is an admin for which the admin role is getting disabled if (await userManager.IsInRoleAsync(user, FshRoles.Admin) - && request.UserRoles.Exists(a => !a.Enabled && a.RoleName == FshRoles.Admin)) + && userRoles.Exists(a => !a.Enabled && a.RoleName == FshRoles.Admin)) { // Get count of users in Admin Role int adminCount = (await userManager.GetUsersInRoleAsync(FshRoles.Admin)).Count; @@ -288,7 +285,7 @@ public async Task AssignRolesAsync(string userId, AssignUserRolesCommand } } - foreach (var userRole in request.UserRoles) + foreach (var userRole in userRoles) { // Check if Role Exists if (await roleManager.FindByNameAsync(userRole.RoleName!) is not null) diff --git a/src/framework/Identity/v1/Roles/RoleService.cs b/src/framework/Identity/v1/Roles/RoleService.cs index fe4f21f75..c52d00fa4 100644 --- a/src/framework/Identity/v1/Roles/RoleService.cs +++ b/src/framework/Identity/v1/Roles/RoleService.cs @@ -2,11 +2,9 @@ using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Identity.Core.Roles; -using FSH.Framework.Identity.Endpoints.v1.Roles.CreateOrUpdateRole; -using FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; using FSH.Framework.Identity.Infrastructure.Data; using FSH.Framework.Identity.Infrastructure.Roles; -using FSH.Framework.Infrastructure.Identity.RoleClaims; +using FSH.Framework.Identity.v1.RoleClaims; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using Microsoft.AspNetCore.Identity; @@ -37,19 +35,19 @@ public async Task> GetRolesAsync() return new RoleDto { Id = role.Id, Name = role.Name!, Description = role.Description }; } - public async Task CreateOrUpdateRoleAsync(UpsertRoleCommand command) + public async Task CreateOrUpdateRoleAsync(string roleId, string name, string description) { - FshRole? role = await _roleManager.FindByIdAsync(command.Id); + FshRole? role = await _roleManager.FindByIdAsync(roleId); if (role != null) { - role.Name = command.Name; - role.Description = command.Description; + role.Name = name; + role.Description = description; await _roleManager.UpdateAsync(role); } else { - role = new FshRole(command.Name, command.Description); + role = new FshRole(name, description); await _roleManager.CreateAsync(role); } @@ -78,9 +76,9 @@ public async Task GetWithPermissionsAsync(string id, CancellationToken return role; } - public async Task UpdatePermissionsAsync(UpdatePermissionsCommand command) + public async Task UpdatePermissionsAsync(string roleId, List permissions) { - var role = await _roleManager.FindByIdAsync(command.RoleId); + var role = await _roleManager.FindByIdAsync(roleId); _ = role ?? throw new NotFoundException("role not found"); if (role.Name == FshRoles.Admin) { @@ -90,13 +88,13 @@ public async Task UpdatePermissionsAsync(UpdatePermissionsCommand comman if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id != TenantConstants.Root.Id) { // Remove Root Permissions if the Role is not created for Root Tenant. - command.Permissions.RemoveAll(u => u.StartsWith("Permissions.Root.", StringComparison.InvariantCultureIgnoreCase)); + permissions.RemoveAll(u => u.StartsWith("Permissions.Root.", StringComparison.InvariantCultureIgnoreCase)); } var currentClaims = await _roleManager.GetClaimsAsync(role); // Remove permissions that were previously selected - foreach (var claim in currentClaims.Where(c => !command.Permissions.Exists(p => p == c.Value))) + foreach (var claim in currentClaims.Where(c => !permissions.Exists(p => p == c.Value))) { var result = await _roleManager.RemoveClaimAsync(role, claim); if (!result.Succeeded) @@ -107,7 +105,7 @@ public async Task UpdatePermissionsAsync(UpdatePermissionsCommand comman } // Add all permissions that were not previously selected - foreach (string permission in command.Permissions.Where(c => !currentClaims.Any(p => p.Value == c))) + foreach (string permission in permissions.Where(c => !currentClaims.Any(p => p.Value == c))) { if (!string.IsNullOrEmpty(permission)) { diff --git a/src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs b/src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs index c23a8f5f4..34601366a 100644 --- a/src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs +++ b/src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs b/src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs index 6ee0f74ee..e0f29ca07 100644 --- a/src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs +++ b/src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs @@ -1,10 +1,10 @@ -using System.Security.Claims; -using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Core.Exceptions; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; +using System.Security.Claims; namespace FSH.Framework.Infrastructure.Identity.Users.Endpoints; public static class GetUserPermissionsEndpoint diff --git a/src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs b/src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs index 9f3ea36ab..525309c45 100644 --- a/src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs +++ b/src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs @@ -1,10 +1,10 @@ using FSH.Framework.Core.Exceptions; -using System.Security.Claims; -using FSH.Framework.Core.Identity.Users.Abstractions; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using FSH.Starter.Shared.Authorization; +using System.Security.Claims; namespace FSH.Framework.Infrastructure.Identity.Users.Endpoints; public static class GetUserProfileEndpoint diff --git a/src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs b/src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs index 0743634ca..bfe89dca8 100644 --- a/src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs +++ b/src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs b/src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs index 84b98a911..6d115b9eb 100644 --- a/src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs +++ b/src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.RegisterUser; -using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; +using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -16,7 +16,15 @@ internal static RouteHandlerBuilder MapRegisterUserEndpoint(this IEndpointRouteB CancellationToken cancellationToken) => { var origin = $"{context.Request.Scheme}://{context.Request.Host.Value}{context.Request.PathBase.Value}"; - return service.RegisterAsync(request, origin, cancellationToken); + return service.RegisterAsync(request.FirstName, + request.LastName, + request.Email, + request.UserName, + request.Password, + request.ConfirmPassword, + request.PhoneNumber, + origin, + cancellationToken); }) .WithName(nameof(RegisterUserEndpoint)) .WithSummary("register user") diff --git a/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs b/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs index a1f718720..d0e63812a 100644 --- a/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs +++ b/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs @@ -1,8 +1,8 @@ using FluentValidation; using FluentValidation.Results; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.ResetPassword; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Endpoints.v1.Users.ResetPassword; +using FSH.Framework.Shared.Constants; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -14,7 +14,11 @@ public static class ResetPasswordEndpoint { internal static RouteHandlerBuilder MapResetPasswordEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/reset-password", async (ResetPasswordCommand command, [FromHeader(Name = TenantConstants.Identifier)] string tenant, IValidator validator, IUserService userService, CancellationToken cancellationToken) => + return endpoints.MapPost("/reset-password", + async (ResetPasswordCommand command, + [FromHeader(Name = TenantConstants.Identifier)] string tenant, + IValidator validator, + IUserService userService, CancellationToken cancellationToken) => { ValidationResult result = await validator.ValidateAsync(command, cancellationToken); if (!result.IsValid) @@ -22,7 +26,7 @@ internal static RouteHandlerBuilder MapResetPasswordEndpoint(this IEndpointRoute return Results.ValidationProblem(result.ToDictionary()); } - await userService.ResetPasswordAsync(command, cancellationToken); + await userService.ResetPasswordAsync(command.Email, command.Password, command.Token, cancellationToken); return Results.Ok("Password has been reset."); }) .WithName(nameof(ResetPasswordEndpoint)) diff --git a/src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs b/src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs index 8af1fc52f..fda5269bf 100644 --- a/src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs +++ b/src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs @@ -1,7 +1,7 @@ -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.RegisterUser; -using FSH.Framework.Infrastructure.Auth.Policy; -using FSH.Starter.Shared.Authorization; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Shared.Constants; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -19,7 +19,15 @@ internal static RouteHandlerBuilder MapSelfRegisterUserEndpoint(this IEndpointRo CancellationToken cancellationToken) => { var origin = $"{context.Request.Scheme}://{context.Request.Host.Value}{context.Request.PathBase.Value}"; - return service.RegisterAsync(request, origin, cancellationToken); + return service.RegisterAsync(request.FirstName, + request.LastName, + request.Email, + request.UserName, + request.Password, + request.ConfirmPassword, + request.PhoneNumber, + origin, + cancellationToken); }) .WithName(nameof(SelfRegisterUserEndpoint)) .WithSummary("self register user") diff --git a/src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs b/src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs index 7e705e329..a2f77305d 100644 --- a/src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs +++ b/src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs @@ -1,6 +1,6 @@ using FluentValidation; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.ToggleUserStatus; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Identity.Endpoints.v1.Users.ToggleUserStatus; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -23,7 +23,7 @@ internal static RouteHandlerBuilder ToggleUserStatusEndpointEndpoint(this IEndpo return Results.BadRequest(); } - await userService.ToggleStatusAsync(command, cancellationToken); + await userService.ToggleStatusAsync(command.ActivateUser, command.UserId, cancellationToken); return Results.Ok(); }) .WithName(nameof(ToggleUserStatusEndpoint)) diff --git a/src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs index dbfd12253..462a8c2db 100644 --- a/src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs +++ b/src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs @@ -1,6 +1,6 @@ using FluentValidation; using FSH.Framework.Core.Storage; -using FSH.Framework.Identity.Endpoints.v1.Users.UpdateUser; +using FSH.Framework.Identity.Contracts.v1.Users.UpdateUser; namespace FSH.Framework.Identity.v1.Users.UpdateUser; public class UpdateUserCommandValidator : AbstractValidator diff --git a/src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs b/src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs index 6d137e8d9..ddd0d2379 100644 --- a/src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs +++ b/src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs @@ -1,26 +1,30 @@ -using System.Security.Claims; -using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.Identity.Users.Abstractions; -using FSH.Framework.Core.Identity.Users.Features.UpdateUser; -using FSH.Framework.Infrastructure.Auth.Policy; -using FSH.Starter.Shared.Authorization; -using MediatR; +using FSH.Framework.Core.Exceptions; +using FSH.Framework.Identity.Contracts.v1.Users.UpdateUser; +using FSH.Framework.Identity.Core.Users; +using FSH.Framework.Shared.Authorization; +using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; +using System.Security.Claims; namespace FSH.Framework.Infrastructure.Identity.Users.Endpoints; public static class UpdateUserEndpoint { internal static RouteHandlerBuilder MapUpdateUserEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPut("/profile", (UpdateUserCommand request, ISender mediator, ClaimsPrincipal user, IUserService service) => + return endpoints.MapPut("/profile", (UpdateUserCommand request, ClaimsPrincipal user, IUserService service) => { if (user.GetUserId() is not { } userId || string.IsNullOrEmpty(userId)) { throw new UnauthorizedException(); } - return service.UpdateAsync(request, userId); + return service.UpdateAsync(request.Id, + request.FirstName, + request.LastName, + request.PhoneNumber, + request.Image, + request.DeleteCurrentImage); }) .WithName(nameof(UpdateUserEndpoint)) .WithSummary("update user profile") diff --git a/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs deleted file mode 100644 index e92cdb2e6..000000000 --- a/src/framework/Infrastructure/Auth/Policy/RequiredPermissionAuthorizationExtensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace FSH.Framework.Infrastructure.Auth.Policy; -public static class RequiredPermissionDefaults -{ - public const string PolicyName = "RequiredPermission"; -} - -public static class RequiredPermissionAuthorizationExtensions -{ - public static AuthorizationPolicyBuilder RequireRequiredPermissions(this AuthorizationPolicyBuilder builder) - { - return builder.AddRequirements(new PermissionAuthorizationRequirement()); - } - - public static AuthorizationBuilder AddRequiredPermissionPolicy(this AuthorizationBuilder builder) - { - builder.AddPolicy(RequiredPermissionDefaults.PolicyName, policy => - { - policy.RequireAuthenticatedUser(); - policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme); - policy.RequireRequiredPermissions(); - }); - - builder.Services.TryAddEnumerable(ServiceDescriptor.Scoped()); - - return builder; - } -} diff --git a/src/framework/Infrastructure/Cors/CorsOptions.cs b/src/framework/Infrastructure/Cors/CorsOptions.cs index 8f2ef1b9e..289b9e3d3 100644 --- a/src/framework/Infrastructure/Cors/CorsOptions.cs +++ b/src/framework/Infrastructure/Cors/CorsOptions.cs @@ -1,6 +1,5 @@ -namespace FSH.Framework.Infrastructure.Cors; -using System.Collections.ObjectModel; - +using System.Collections.ObjectModel; +namespace FSH.Framework.Infrastructure.Cors; public class CorsOptions { public CorsOptions() diff --git a/src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs b/src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs index c2d19308f..e4c5ed7ef 100644 --- a/src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs +++ b/src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs @@ -20,7 +20,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e problemDetails.Detail = "one or more validation errors occurred"; problemDetails.Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1"; httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; - List validationErrors = new List(); + List validationErrors = new(); foreach (var error in fluentException.Errors) { validationErrors.Add(error.ErrorMessage); @@ -28,7 +28,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e problemDetails.Extensions.Add("errors", validationErrors); } - else if (exception is FshException e) + else if (exception is CustomException e) { httpContext.Response.StatusCode = (int)e.StatusCode; problemDetails.Detail = e.Message; diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs index 634c81a62..ed027e12b 100644 --- a/src/framework/Infrastructure/Extensions.cs +++ b/src/framework/Infrastructure/Extensions.cs @@ -2,7 +2,6 @@ using FluentValidation; using FSH.Framework.Core; using FSH.Framework.Core.Origin; -using FSH.Framework.Infrastructure.Auth.Jwt; using FSH.Framework.Infrastructure.Caching; using FSH.Framework.Infrastructure.Cors; using FSH.Framework.Infrastructure.Exceptions; @@ -31,7 +30,6 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui builder.ConfigureDatabase(); builder.Services.AddCorsPolicy(builder.Configuration); builder.Services.ConfigureLocalFileStorage(); - builder.Services.ConfigureJwtAuth(); builder.Services.ConfigureOpenApi(); builder.Services.ConfigureJobs(builder.Configuration); builder.Services.ConfigureMailing(); diff --git a/src/framework/Infrastructure/Infrastructure.csproj b/src/framework/Infrastructure/Infrastructure.csproj index d152b6a19..7ec135554 100644 --- a/src/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Infrastructure/Infrastructure.csproj @@ -59,8 +59,5 @@ - - - diff --git a/src/framework/Infrastructure/Jobs/Extensions.cs b/src/framework/Infrastructure/Jobs/Extensions.cs index 618d07d30..2e8197400 100644 --- a/src/framework/Infrastructure/Jobs/Extensions.cs +++ b/src/framework/Infrastructure/Jobs/Extensions.cs @@ -15,7 +15,7 @@ internal static class Extensions internal static IServiceCollection ConfigureJobs(this IServiceCollection services, IConfiguration configuration) { var dbOptions = configuration.GetSection(nameof(DatabaseOptions)).Get() ?? - throw new FshException("database options cannot be null"); + throw new CustomException("database options cannot be null"); services.AddHangfireServer(o => { @@ -41,7 +41,7 @@ internal static IServiceCollection ConfigureJobs(this IServiceCollection service break; default: - throw new FshException($"hangfire storage provider {dbOptions.Provider} is not supported"); + throw new CustomException($"hangfire storage provider {dbOptions.Provider} is not supported"); } config.UseFilter(new FshJobFilter(provider)); diff --git a/src/framework/Infrastructure/Mail/SmtpMailService.cs b/src/framework/Infrastructure/Mail/SmtpMailService.cs index aee596949..80b90a40c 100644 --- a/src/framework/Infrastructure/Mail/SmtpMailService.cs +++ b/src/framework/Infrastructure/Mail/SmtpMailService.cs @@ -1,9 +1,4 @@ -namespace FSH.Framework.Infrastructure.Mail; -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; + using FSH.Framework.Core.Mail; using MailKit.Net.Smtp; using MailKit.Security; @@ -11,6 +6,8 @@ using Microsoft.Extensions.Options; using MimeKit; +namespace FSH.Framework.Infrastructure.Mail; + public class SmtpMailService(IOptions settings, ILogger logger) : IMailService { private readonly MailOptions _settings = settings.Value; @@ -63,12 +60,10 @@ public async Task SendAsync(MailRequest request, CancellationToken ct) { foreach (var attachmentInfo in request.AttachmentData) { - using (var stream = new MemoryStream()) - { - await stream.WriteAsync(attachmentInfo.Value, ct); - stream.Position = 0; - await builder.Attachments.AddAsync(attachmentInfo.Key, stream, ct); - } + using var stream = new MemoryStream(); + await stream.WriteAsync(attachmentInfo.Value, ct); + stream.Position = 0; + await builder.Attachments.AddAsync(attachmentInfo.Key, stream, ct); } } diff --git a/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs b/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs index b71f418bf..0ca6e89ae 100644 --- a/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs +++ b/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs @@ -1,15 +1,19 @@ using FSH.Framework.Auditing.Contracts.Enums; +using System.Collections.ObjectModel; namespace FSH.Framework.Auditing.Contracts.Dtos; -public record TrailDto( - Guid Id, - DateTimeOffset DateTime, - Guid UserId, - AuditOperation Operation, - string Description, - string EntityName -//Dictionary KeyValues, -//Dictionary OldValues, -//Dictionary NewValues, -//Collection ModifiedProperties -); \ No newline at end of file +public class TrailDto +{ + public Guid Id { get; set; } + public DateTimeOffset DateTime { get; set; } + public Guid UserId { get; set; } + public AuditOperation Operation { get; set; } + public string Description { get; set; } = default!; + public string EntityName { get; set; } = default!; + + // Uncomment if needed later + public Dictionary KeyValues { get; set; } = new(); + public Dictionary OldValues { get; set; } = new(); + public Dictionary NewValues { get; set; } = new(); + public Collection ModifiedProperties { get; set; } = new(); +} diff --git a/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs b/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs index cec40ea07..ee130b6ed 100644 --- a/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs +++ b/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs @@ -64,12 +64,12 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData, Cancell { case EntityState.Added: audit.Operation = AuditOperation.Create; - audit.SetNewValue(propertyName, property.CurrentValue); + audit.NewValues[propertyName] = property.CurrentValue; break; case EntityState.Deleted: audit.Operation = AuditOperation.Delete; - audit.SetOldValue(propertyName, property.OriginalValue); + audit.OldValues[propertyName] = property.OriginalValue; break; case EntityState.Modified: @@ -77,17 +77,17 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData, Cancell { if (entry.Entity is ISoftDeletable && property.OriginalValue == null && property.CurrentValue != null) { - audit.AddModifiedProperty(propertyName); + audit.ModifiedProperties.Add(propertyName); audit.Operation = AuditOperation.Delete; - audit.SetOldValue(propertyName, property.OriginalValue); - audit.SetNewValue(propertyName, property.CurrentValue); + audit.OldValues[propertyName] = property.OriginalValue; + audit.NewValues[propertyName] = property.CurrentValue; } else if (property.OriginalValue?.Equals(property.CurrentValue) == false) { - audit.AddModifiedProperty(propertyName); + audit.ModifiedProperties.Add(propertyName); audit.Operation = AuditOperation.Update; - audit.SetOldValue(propertyName, property.OriginalValue); - audit.SetNewValue(propertyName, property.CurrentValue); + audit.OldValues[propertyName] = property.OriginalValue; + audit.NewValues[propertyName] = property.CurrentValue; } else { diff --git a/src/framework/Modules/Auditing/Mappings/TrailMappings.cs b/src/framework/Modules/Auditing/Mappings/TrailMappings.cs index 52bcd9f86..8fd638387 100644 --- a/src/framework/Modules/Auditing/Mappings/TrailMappings.cs +++ b/src/framework/Modules/Auditing/Mappings/TrailMappings.cs @@ -8,20 +8,22 @@ public static class TrailMappings { public static TrailDto ToDto(this Trail trail) { - return new( - Id: trail.Id, - DateTime: trail.DateTime, - UserId: trail.UserId, - Operation: trail.Operation, - Description: trail.Description, - EntityName: trail.EntityName ?? string.Empty, - KeyValues: new Dictionary(trail.KeyValues), - OldValues: new Dictionary(trail.OldValues), - NewValues: new Dictionary(trail.NewValues), - ModifiedProperties: new Collection(trail.ModifiedProperties.ToList()) - ); + return new TrailDto + { + Id = trail.Id, + DateTime = trail.DateTime, + UserId = trail.UserId, + Operation = trail.Operation, + Description = trail.Description, + EntityName = trail.EntityName ?? string.Empty, + KeyValues = new Dictionary(trail.KeyValues), + OldValues = new Dictionary(trail.OldValues), + NewValues = new Dictionary(trail.NewValues), + ModifiedProperties = new Collection(trail.ModifiedProperties.ToList()) + }; } + public static IReadOnlyList ToDtoList(this IEnumerable trails) { return trails.Select(t => t.ToDto()).ToList(); From ec38bae664a3e8d389c3b7b559010b395009aa87 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 16 Apr 2025 13:58:59 +0530 Subject: [PATCH 31/54] cleanup --- src/framework/FSH.Framework.sln | 59 ++++++++----------- .../Identity.Contracts/Dtos/RoleDto.cs | 0 .../Identity.Contracts/Dtos/TokenDto.cs | 0 .../Identity.Contracts/Dtos/UserDto.cs | 0 .../Identity.Contracts/Dtos/UserRoleDto.cs | 0 .../Identity.Contracts.csproj | 2 +- .../IdentityModuleConstants.cs | 0 .../UpdatePermissionsCommand.cs | 0 .../v1/Roles/UpsertRole/UpsertRoleCommand.cs | 0 .../RefreshToken/RefreshTokenCommand.cs | 0 .../RefreshTokenCommandResponse.cs | 0 .../TokenGeneration/TokenGenerationCommand.cs | 0 .../TokenGenerationCommandResponse.cs | 0 .../AssignUserRoles/AssignUserRolesCommand.cs | 0 .../AssignUserRolesCommandResponse.cs | 0 .../ChangePassword/ChangePasswordCommand.cs | 0 .../ForgotPassword/ForgotPasswordCommand.cs | 0 .../Users/RegisterUser/RegisterUserCommand.cs | 0 .../RegisterUser/RegisterUserResponse.cs | 0 .../ResetPassword/ResetPasswordCommand.cs | 0 .../ToggleUserStatusCommand.cs | 0 .../v1/Users/UpdateUser/UpdateUserCommand.cs | 0 .../Authorization/CurrentUserMiddleware.cs | 0 .../Identity/Authorization/Jwt/Extensions.cs | 0 .../PermissionAuthorizationRequirement.cs | 0 ...quiredPermissionAuthorizationExtensions.cs | 0 .../RequiredPermissionAuthorizationHandler.cs | 0 .../Identity/Data/IdentityConfigurations.cs | 0 .../Identity/Data/IdentityDbContext.cs | 0 .../Identity/Data/IdentityDbInitializer.cs | 0 .../{ => Modules}/Identity/Identity.csproj | 6 +- .../{ => Modules}/Identity/IdentityModule.cs | 0 .../Options/ConfigureJwtBearerOptions.cs | 0 .../Identity/Options/JwtOptions.cs | 0 .../Identity/Services/CurrentUserService.cs | 0 .../Identity/Services/IRoleService.cs | 0 .../Identity/Services/ITokenService.cs | 0 .../Identity/Services/IUserService.cs | 0 .../Identity/Services/TokenService.cs | 0 .../Identity/Services/UserService.Password.cs | 0 .../Services/UserService.Permissions.cs | 0 .../Identity/Services/UserService.cs | 0 .../Identity/v1/RoleClaims/FshRoleClaim.cs | 0 .../v1/Roles/DeleteRole/DeleteRoleEndpoint.cs | 0 .../Identity/v1/Roles/FshRole.cs | 0 .../v1/Roles/GetRole/GetRoleEndpoint.cs | 0 .../GetRolePermissionsEndpoint.cs | 0 .../v1/Roles/GetRoles/GetRolesEndpoint.cs | 0 .../Identity/v1/Roles/RoleService.cs | 0 .../UpdatePermissionsCommandValidator.cs | 0 .../UpdateRolePermissionsEndpoint.cs | 0 .../UpsertRole/CreateOrUpdateRoleEndpoint.cs | 0 .../UpsertRole/UpsertRoleCommandValidator.cs | 0 .../RefreshTokenCommandHandler.cs | 0 .../RefreshTokenCommandValidator.cs | 0 .../RefreshToken/RefreshTokenEndpoint.cs | 0 .../TokenGenerationCommandHandler.cs | 0 .../TokenGenerationCommandValidator.cs | 0 .../TokenGenerationEndpoint.cs | 0 .../AssignUserRolesCommandHandler.cs | 0 .../AssignUserRolesEndpoint.cs | 0 .../ChangePassword/ChangePasswordEndpoint.cs | 0 .../ChangePassword/ChangePasswordValidator.cs | 0 .../ConfirmEmail/ConfirmEmailEndpoint.cs | 0 .../v1/Users/DeleteUser/DeleteUserEndpoint.cs | 0 .../ForgotPasswordCommandValidator.cs | 0 .../ForgotPassword/ForgotPasswordEndpoint.cs | 0 .../Identity/v1/Users/FshUser.cs | 0 .../v1/Users/GetUser/GetUserEndpoint.cs | 0 .../GetUserPermissionsEndpoint.cs | 0 .../GetUserProfile/GetUserProfileEndpoint.cs | 0 .../GetUserRoles/GetUserRolesEndpoint.cs | 0 .../v1/Users/GetUsers/GetUsersListEndpoint.cs | 0 .../RegisterUser/RegisterUserEndpoint.cs | 0 .../ResetPasswordCommandValidator.cs | 0 .../ResetPassword/ResetPasswordEndpoint.cs | 0 .../SelfRegisterUserEndpoint.cs | 0 .../ToggleUserStatusEndpoint.cs | 0 .../UpdateUser/UpdateUserCommandValidator.cs | 0 .../v1/Users/UpdateUser/UpdateUserEndpoint.cs | 0 80 files changed, 29 insertions(+), 38 deletions(-) rename src/framework/{ => Modules}/Identity.Contracts/Dtos/RoleDto.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/Dtos/TokenDto.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/Dtos/UserDto.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/Dtos/UserRoleDto.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/Identity.Contracts.csproj (87%) rename src/framework/{ => Modules}/Identity.Contracts/IdentityModuleConstants.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs (100%) rename src/framework/{ => Modules}/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs (100%) rename src/framework/{ => Modules}/Identity/Authorization/CurrentUserMiddleware.cs (100%) rename src/framework/{ => Modules}/Identity/Authorization/Jwt/Extensions.cs (100%) rename src/framework/{ => Modules}/Identity/Authorization/PermissionAuthorizationRequirement.cs (100%) rename src/framework/{ => Modules}/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs (100%) rename src/framework/{ => Modules}/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs (100%) rename src/framework/{ => Modules}/Identity/Data/IdentityConfigurations.cs (100%) rename src/framework/{ => Modules}/Identity/Data/IdentityDbContext.cs (100%) rename src/framework/{ => Modules}/Identity/Data/IdentityDbInitializer.cs (100%) rename src/framework/{ => Modules}/Identity/Identity.csproj (67%) rename src/framework/{ => Modules}/Identity/IdentityModule.cs (100%) rename src/framework/{ => Modules}/Identity/Options/ConfigureJwtBearerOptions.cs (100%) rename src/framework/{ => Modules}/Identity/Options/JwtOptions.cs (100%) rename src/framework/{ => Modules}/Identity/Services/CurrentUserService.cs (100%) rename src/framework/{ => Modules}/Identity/Services/IRoleService.cs (100%) rename src/framework/{ => Modules}/Identity/Services/ITokenService.cs (100%) rename src/framework/{ => Modules}/Identity/Services/IUserService.cs (100%) rename src/framework/{ => Modules}/Identity/Services/TokenService.cs (100%) rename src/framework/{ => Modules}/Identity/Services/UserService.Password.cs (100%) rename src/framework/{ => Modules}/Identity/Services/UserService.Permissions.cs (100%) rename src/framework/{ => Modules}/Identity/Services/UserService.cs (100%) rename src/framework/{ => Modules}/Identity/v1/RoleClaims/FshRoleClaim.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/FshRole.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/RoleService.cs (100%) rename src/framework/{Identity.Contracts/v1/Roles/UpdatePermissions => Modules/Identity/v1/Roles/UpdateRolePermissions}/UpdatePermissionsCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs (100%) rename src/framework/{Identity.Contracts => Modules/Identity}/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/FshUser.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/GetUser/GetUserEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs (100%) rename src/framework/{ => Modules}/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs (100%) diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 4b4ec5156..f3368e66f 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -7,34 +7,28 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{60DF219E-E1EB-428E-BB1F-F0342D42699F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{15EA2212-0958-4415-AA37-116F2A47F23F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tenant", "Tenant", "{24E922E3-8C91-43A1-A110-D8F5276566BA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auditing", "Auditing", "{E5141F38-2D08-44DA-9A6C-B96890515168}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{09380C15-F138-4305-A595-F4C7E16B6E78}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props - EndProjectSection -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing", "Modules\Auditing\Auditing.csproj", "{BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Contracts", "Modules\Auditing.Contracts\Auditing.Contracts.csproj", "{E39A5A4F-D453-A6A2-CA94-468FD795246C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity", "Modules\Identity\Identity.csproj", "{CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Contracts", "Modules\Identity.Contracts\Identity.Contracts.csproj", "{201606BA-48CE-42F0-B31F-596187F40B2F}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant", "Modules\Tenant\Tenant.csproj", "{27806993-447E-9781-647B-06D3F4AC834A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Contracts", "Modules\Tenant.Contracts\Tenant.Contracts.csproj", "{5324A0FF-DBB9-440C-80C2-4891EC719155}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity", "Identity\Identity.csproj", "{CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Contracts", "Identity.Contracts\Identity.Contracts.csproj", "{201606BA-48CE-42F0-B31F-596187F40B2F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -62,14 +56,6 @@ Global {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Debug|Any CPU.Build.0 = Debug|Any CPU {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Release|Any CPU.ActiveCfg = Release|Any CPU {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Release|Any CPU.Build.0 = Release|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.Build.0 = Release|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.Build.0 = Release|Any CPU {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -78,22 +64,27 @@ Global {201606BA-48CE-42F0-B31F-596187F40B2F}.Debug|Any CPU.Build.0 = Debug|Any CPU {201606BA-48CE-42F0-B31F-596187F40B2F}.Release|Any CPU.ActiveCfg = Release|Any CPU {201606BA-48CE-42F0-B31F-596187F40B2F}.Release|Any CPU.Build.0 = Release|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.Build.0 = Release|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {15EA2212-0958-4415-AA37-116F2A47F23F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {24E922E3-8C91-43A1-A110-D8F5276566BA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {E5141F38-2D08-44DA-9A6C-B96890515168} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B} = {E5141F38-2D08-44DA-9A6C-B96890515168} - {E39A5A4F-D453-A6A2-CA94-468FD795246C} = {E5141F38-2D08-44DA-9A6C-B96890515168} - {27806993-447E-9781-647B-06D3F4AC834A} = {24E922E3-8C91-43A1-A110-D8F5276566BA} - {5324A0FF-DBB9-440C-80C2-4891EC719155} = {24E922E3-8C91-43A1-A110-D8F5276566BA} - {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD} = {15EA2212-0958-4415-AA37-116F2A47F23F} - {201606BA-48CE-42F0-B31F-596187F40B2F} = {15EA2212-0958-4415-AA37-116F2A47F23F} + {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {E39A5A4F-D453-A6A2-CA94-468FD795246C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {201606BA-48CE-42F0-B31F-596187F40B2F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {27806993-447E-9781-647B-06D3F4AC834A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {5324A0FF-DBB9-440C-80C2-4891EC719155} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} + SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} EndGlobalSection EndGlobal diff --git a/src/framework/Identity.Contracts/Dtos/RoleDto.cs b/src/framework/Modules/Identity.Contracts/Dtos/RoleDto.cs similarity index 100% rename from src/framework/Identity.Contracts/Dtos/RoleDto.cs rename to src/framework/Modules/Identity.Contracts/Dtos/RoleDto.cs diff --git a/src/framework/Identity.Contracts/Dtos/TokenDto.cs b/src/framework/Modules/Identity.Contracts/Dtos/TokenDto.cs similarity index 100% rename from src/framework/Identity.Contracts/Dtos/TokenDto.cs rename to src/framework/Modules/Identity.Contracts/Dtos/TokenDto.cs diff --git a/src/framework/Identity.Contracts/Dtos/UserDto.cs b/src/framework/Modules/Identity.Contracts/Dtos/UserDto.cs similarity index 100% rename from src/framework/Identity.Contracts/Dtos/UserDto.cs rename to src/framework/Modules/Identity.Contracts/Dtos/UserDto.cs diff --git a/src/framework/Identity.Contracts/Dtos/UserRoleDto.cs b/src/framework/Modules/Identity.Contracts/Dtos/UserRoleDto.cs similarity index 100% rename from src/framework/Identity.Contracts/Dtos/UserRoleDto.cs rename to src/framework/Modules/Identity.Contracts/Dtos/UserRoleDto.cs diff --git a/src/framework/Identity.Contracts/Identity.Contracts.csproj b/src/framework/Modules/Identity.Contracts/Identity.Contracts.csproj similarity index 87% rename from src/framework/Identity.Contracts/Identity.Contracts.csproj rename to src/framework/Modules/Identity.Contracts/Identity.Contracts.csproj index 650b6a582..70642d051 100644 --- a/src/framework/Identity.Contracts/Identity.Contracts.csproj +++ b/src/framework/Modules/Identity.Contracts/Identity.Contracts.csproj @@ -9,7 +9,7 @@ enable - + diff --git a/src/framework/Identity.Contracts/IdentityModuleConstants.cs b/src/framework/Modules/Identity.Contracts/IdentityModuleConstants.cs similarity index 100% rename from src/framework/Identity.Contracts/IdentityModuleConstants.cs rename to src/framework/Modules/Identity.Contracts/IdentityModuleConstants.cs diff --git a/src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs b/src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs rename to src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs diff --git a/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs b/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs rename to src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs diff --git a/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs b/src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs diff --git a/src/framework/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs b/src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs diff --git a/src/framework/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs diff --git a/src/framework/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs rename to src/framework/Modules/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs diff --git a/src/framework/Identity/Authorization/CurrentUserMiddleware.cs b/src/framework/Modules/Identity/Authorization/CurrentUserMiddleware.cs similarity index 100% rename from src/framework/Identity/Authorization/CurrentUserMiddleware.cs rename to src/framework/Modules/Identity/Authorization/CurrentUserMiddleware.cs diff --git a/src/framework/Identity/Authorization/Jwt/Extensions.cs b/src/framework/Modules/Identity/Authorization/Jwt/Extensions.cs similarity index 100% rename from src/framework/Identity/Authorization/Jwt/Extensions.cs rename to src/framework/Modules/Identity/Authorization/Jwt/Extensions.cs diff --git a/src/framework/Identity/Authorization/PermissionAuthorizationRequirement.cs b/src/framework/Modules/Identity/Authorization/PermissionAuthorizationRequirement.cs similarity index 100% rename from src/framework/Identity/Authorization/PermissionAuthorizationRequirement.cs rename to src/framework/Modules/Identity/Authorization/PermissionAuthorizationRequirement.cs diff --git a/src/framework/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs similarity index 100% rename from src/framework/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs rename to src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs diff --git a/src/framework/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs similarity index 100% rename from src/framework/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs rename to src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs diff --git a/src/framework/Identity/Data/IdentityConfigurations.cs b/src/framework/Modules/Identity/Data/IdentityConfigurations.cs similarity index 100% rename from src/framework/Identity/Data/IdentityConfigurations.cs rename to src/framework/Modules/Identity/Data/IdentityConfigurations.cs diff --git a/src/framework/Identity/Data/IdentityDbContext.cs b/src/framework/Modules/Identity/Data/IdentityDbContext.cs similarity index 100% rename from src/framework/Identity/Data/IdentityDbContext.cs rename to src/framework/Modules/Identity/Data/IdentityDbContext.cs diff --git a/src/framework/Identity/Data/IdentityDbInitializer.cs b/src/framework/Modules/Identity/Data/IdentityDbInitializer.cs similarity index 100% rename from src/framework/Identity/Data/IdentityDbInitializer.cs rename to src/framework/Modules/Identity/Data/IdentityDbInitializer.cs diff --git a/src/framework/Identity/Identity.csproj b/src/framework/Modules/Identity/Identity.csproj similarity index 67% rename from src/framework/Identity/Identity.csproj rename to src/framework/Modules/Identity/Identity.csproj index 740e5af9e..f7a276acf 100644 --- a/src/framework/Identity/Identity.csproj +++ b/src/framework/Modules/Identity/Identity.csproj @@ -9,9 +9,9 @@ enable + + + - - - diff --git a/src/framework/Identity/IdentityModule.cs b/src/framework/Modules/Identity/IdentityModule.cs similarity index 100% rename from src/framework/Identity/IdentityModule.cs rename to src/framework/Modules/Identity/IdentityModule.cs diff --git a/src/framework/Identity/Options/ConfigureJwtBearerOptions.cs b/src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs similarity index 100% rename from src/framework/Identity/Options/ConfigureJwtBearerOptions.cs rename to src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs diff --git a/src/framework/Identity/Options/JwtOptions.cs b/src/framework/Modules/Identity/Options/JwtOptions.cs similarity index 100% rename from src/framework/Identity/Options/JwtOptions.cs rename to src/framework/Modules/Identity/Options/JwtOptions.cs diff --git a/src/framework/Identity/Services/CurrentUserService.cs b/src/framework/Modules/Identity/Services/CurrentUserService.cs similarity index 100% rename from src/framework/Identity/Services/CurrentUserService.cs rename to src/framework/Modules/Identity/Services/CurrentUserService.cs diff --git a/src/framework/Identity/Services/IRoleService.cs b/src/framework/Modules/Identity/Services/IRoleService.cs similarity index 100% rename from src/framework/Identity/Services/IRoleService.cs rename to src/framework/Modules/Identity/Services/IRoleService.cs diff --git a/src/framework/Identity/Services/ITokenService.cs b/src/framework/Modules/Identity/Services/ITokenService.cs similarity index 100% rename from src/framework/Identity/Services/ITokenService.cs rename to src/framework/Modules/Identity/Services/ITokenService.cs diff --git a/src/framework/Identity/Services/IUserService.cs b/src/framework/Modules/Identity/Services/IUserService.cs similarity index 100% rename from src/framework/Identity/Services/IUserService.cs rename to src/framework/Modules/Identity/Services/IUserService.cs diff --git a/src/framework/Identity/Services/TokenService.cs b/src/framework/Modules/Identity/Services/TokenService.cs similarity index 100% rename from src/framework/Identity/Services/TokenService.cs rename to src/framework/Modules/Identity/Services/TokenService.cs diff --git a/src/framework/Identity/Services/UserService.Password.cs b/src/framework/Modules/Identity/Services/UserService.Password.cs similarity index 100% rename from src/framework/Identity/Services/UserService.Password.cs rename to src/framework/Modules/Identity/Services/UserService.Password.cs diff --git a/src/framework/Identity/Services/UserService.Permissions.cs b/src/framework/Modules/Identity/Services/UserService.Permissions.cs similarity index 100% rename from src/framework/Identity/Services/UserService.Permissions.cs rename to src/framework/Modules/Identity/Services/UserService.Permissions.cs diff --git a/src/framework/Identity/Services/UserService.cs b/src/framework/Modules/Identity/Services/UserService.cs similarity index 100% rename from src/framework/Identity/Services/UserService.cs rename to src/framework/Modules/Identity/Services/UserService.cs diff --git a/src/framework/Identity/v1/RoleClaims/FshRoleClaim.cs b/src/framework/Modules/Identity/v1/RoleClaims/FshRoleClaim.cs similarity index 100% rename from src/framework/Identity/v1/RoleClaims/FshRoleClaim.cs rename to src/framework/Modules/Identity/v1/RoleClaims/FshRoleClaim.cs diff --git a/src/framework/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs rename to src/framework/Modules/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs diff --git a/src/framework/Identity/v1/Roles/FshRole.cs b/src/framework/Modules/Identity/v1/Roles/FshRole.cs similarity index 100% rename from src/framework/Identity/v1/Roles/FshRole.cs rename to src/framework/Modules/Identity/v1/Roles/FshRole.cs diff --git a/src/framework/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs rename to src/framework/Modules/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs diff --git a/src/framework/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs rename to src/framework/Modules/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs diff --git a/src/framework/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs rename to src/framework/Modules/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs diff --git a/src/framework/Identity/v1/Roles/RoleService.cs b/src/framework/Modules/Identity/v1/Roles/RoleService.cs similarity index 100% rename from src/framework/Identity/v1/Roles/RoleService.cs rename to src/framework/Modules/Identity/v1/Roles/RoleService.cs diff --git a/src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommandValidator.cs b/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommandValidator.cs rename to src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs diff --git a/src/framework/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs rename to src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs diff --git a/src/framework/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs rename to src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs diff --git a/src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs b/src/framework/Modules/Identity/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs similarity index 100% rename from src/framework/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs rename to src/framework/Modules/Identity/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs diff --git a/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs b/src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs similarity index 100% rename from src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs rename to src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs diff --git a/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs b/src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs similarity index 100% rename from src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs rename to src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs diff --git a/src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs b/src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs rename to src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs diff --git a/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs similarity index 100% rename from src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs rename to src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs diff --git a/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs similarity index 100% rename from src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs rename to src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs diff --git a/src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs rename to src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs diff --git a/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs b/src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs similarity index 100% rename from src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs rename to src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs diff --git a/src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs b/src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs diff --git a/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs diff --git a/src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs similarity index 100% rename from src/framework/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs rename to src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs diff --git a/src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs diff --git a/src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs b/src/framework/Modules/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs diff --git a/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs b/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs similarity index 100% rename from src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs rename to src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs diff --git a/src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs diff --git a/src/framework/Identity/v1/Users/FshUser.cs b/src/framework/Modules/Identity/v1/Users/FshUser.cs similarity index 100% rename from src/framework/Identity/v1/Users/FshUser.cs rename to src/framework/Modules/Identity/v1/Users/FshUser.cs diff --git a/src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs b/src/framework/Modules/Identity/v1/Users/GetUser/GetUserEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/GetUser/GetUserEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/GetUser/GetUserEndpoint.cs diff --git a/src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs b/src/framework/Modules/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs diff --git a/src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs b/src/framework/Modules/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs diff --git a/src/framework/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs b/src/framework/Modules/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs diff --git a/src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs b/src/framework/Modules/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs diff --git a/src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs b/src/framework/Modules/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs diff --git a/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs b/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs similarity index 100% rename from src/framework/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs rename to src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs diff --git a/src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs diff --git a/src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs b/src/framework/Modules/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs diff --git a/src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs diff --git a/src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs similarity index 100% rename from src/framework/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs rename to src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs diff --git a/src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs b/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs similarity index 100% rename from src/framework/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs rename to src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs From f45ca56ba557c7f7df6d8713f384a29a7450f267 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 16 Apr 2025 14:23:00 +0530 Subject: [PATCH 32/54] add playground --- src/framework/Directory.Packages.props | 38 ++++++++--------- src/framework/FSH.Framework.sln | 7 ++++ .../PlayGround.Api/PlayGround.Api.csproj | 13 ++++++ .../PlayGround.Api/PlayGround.Api.http | 6 +++ src/framework/PlayGround.Api/Program.cs | 41 +++++++++++++++++++ .../Properties/launchSettings.json | 23 +++++++++++ .../appsettings.Development.json | 8 ++++ src/framework/PlayGround.Api/appsettings.json | 9 ++++ 8 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 src/framework/PlayGround.Api/PlayGround.Api.csproj create mode 100644 src/framework/PlayGround.Api/PlayGround.Api.http create mode 100644 src/framework/PlayGround.Api/Program.cs create mode 100644 src/framework/PlayGround.Api/Properties/launchSettings.json create mode 100644 src/framework/PlayGround.Api/appsettings.Development.json create mode 100644 src/framework/PlayGround.Api/appsettings.json diff --git a/src/framework/Directory.Packages.props b/src/framework/Directory.Packages.props index 3b0367faf..bd4e4d234 100644 --- a/src/framework/Directory.Packages.props +++ b/src/framework/Directory.Packages.props @@ -10,40 +10,40 @@ - + - - - + + + - - - - - - - - - + + + + + + + + + - + - - + + - + @@ -55,8 +55,8 @@ - - + + diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index f3368e66f..325dd4974 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -30,6 +30,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Packages.props = Directory.Packages.props EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayGround.Api", "PlayGround.Api\PlayGround.Api.csproj", "{BAC875BB-D97F-4E06-AFBB-5BB732582908}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,6 +74,10 @@ Global {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.Build.0 = Debug|Any CPU {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.ActiveCfg = Release|Any CPU {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.Build.0 = Release|Any CPU + {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -86,5 +92,6 @@ Global EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} + SolutionGuid = {438A0F87-0F3E-43C4-A352-264E0C21F77B} EndGlobalSection EndGlobal diff --git a/src/framework/PlayGround.Api/PlayGround.Api.csproj b/src/framework/PlayGround.Api/PlayGround.Api.csproj new file mode 100644 index 000000000..203645a61 --- /dev/null +++ b/src/framework/PlayGround.Api/PlayGround.Api.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/src/framework/PlayGround.Api/PlayGround.Api.http b/src/framework/PlayGround.Api/PlayGround.Api.http new file mode 100644 index 000000000..09a4f04b4 --- /dev/null +++ b/src/framework/PlayGround.Api/PlayGround.Api.http @@ -0,0 +1,6 @@ +@PlayGround.Api_HostAddress = http://localhost:5153 + +GET {{PlayGround.Api_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/src/framework/PlayGround.Api/Program.cs b/src/framework/PlayGround.Api/Program.cs new file mode 100644 index 000000000..ad8699de7 --- /dev/null +++ b/src/framework/PlayGround.Api/Program.cs @@ -0,0 +1,41 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => +{ + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; +}) +.WithName("GetWeatherForecast"); + +app.Run(); + +internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/src/framework/PlayGround.Api/Properties/launchSettings.json b/src/framework/PlayGround.Api/Properties/launchSettings.json new file mode 100644 index 000000000..980b6b394 --- /dev/null +++ b/src/framework/PlayGround.Api/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5153", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7044;http://localhost:5153", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/framework/PlayGround.Api/appsettings.Development.json b/src/framework/PlayGround.Api/appsettings.Development.json new file mode 100644 index 000000000..0c208ae91 --- /dev/null +++ b/src/framework/PlayGround.Api/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/framework/PlayGround.Api/appsettings.json b/src/framework/PlayGround.Api/appsettings.json new file mode 100644 index 000000000..10f68b8c8 --- /dev/null +++ b/src/framework/PlayGround.Api/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} From 0c126fc8d36de2ad0becea425695811d47d09ca0 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 16 Apr 2025 18:11:03 +0530 Subject: [PATCH 33/54] cleanup --- src/framework/Directory.Packages.props | 1 + src/framework/FSH.Framework.sln | 22 +- src/framework/Infrastructure/Extensions.cs | 29 +- .../Messaging/CQRS/Extensions.cs | 4 +- .../Infrastructure/OpenApi/Extensions.cs | 51 ++- .../Infrastructure/Persistence/Extensions.cs | 7 +- .../Modules/Auditing/AuditingModule.cs | 3 +- .../PathAwareAuthorizationHandler.cs | 37 ++ .../Modules/Identity/IdentityModule.cs | 33 +- .../UpdateRolePermissionsEndpoint.cs | 2 +- .../UpsertRole/CreateOrUpdateRoleEndpoint.cs | 3 +- .../TokenGenerationEndpoint.cs | 7 +- .../ForgotPassword/ForgotPasswordEndpoint.cs | 2 +- .../ResetPassword/ResetPasswordEndpoint.cs | 2 +- .../ToggleUserStatusEndpoint.cs | 4 +- .../UpdateUser/UpdateUserCommandValidator.cs | 2 +- .../v1/Users/UpdateUser/UpdateUserEndpoint.cs | 3 +- .../Identity/v1/Users/UserImageValidator.cs} | 8 +- .../v1/CreateTenant/CreateTenantEndpoint.cs | 5 +- .../v1/UpgradeTenant/UpgradeTenantEndpoint.cs | 3 +- src/framework/Modules/Tenant/TenantModule.cs | 17 +- .../PlayGround.Api/PlayGround.Api.csproj | 13 - src/framework/PlayGround.Api/Program.cs | 41 -- src/framework/PlayGround.Api/appsettings.json | 9 - .../PlayGround.Api/PlayGround.Api.csproj | 30 ++ .../PlayGround.Api/PlayGround.Api.http | 0 .../playground/PlayGround.Api/Program.cs | 24 ++ .../Properties/launchSettings.json | 12 +- .../appsettings.Development.json | 0 .../PlayGround.Api/appsettings.json | 68 ++++ ...0416110641_Add Identity Schema.Designer.cs | 357 ++++++++++++++++++ .../20250416110641_Add Identity Schema.cs | 268 +++++++++++++ .../IdentityDbContextModelSnapshot.cs | 354 +++++++++++++++++ .../migrations/PostgreSQL/PostgreSQL.csproj | 19 + ...250416110812_Add Tenant Schema.Designer.cs | 69 ++++ .../20250416110812_Add Tenant Schema.cs | 50 +++ .../Tenant/TenantDbContextModelSnapshot.cs | 66 ++++ 37 files changed, 1468 insertions(+), 157 deletions(-) create mode 100644 src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs rename src/framework/{Core/Storage/FileUploadRequestValidator.cs => Modules/Identity/v1/Users/UserImageValidator.cs} (74%) delete mode 100644 src/framework/PlayGround.Api/PlayGround.Api.csproj delete mode 100644 src/framework/PlayGround.Api/Program.cs delete mode 100644 src/framework/PlayGround.Api/appsettings.json create mode 100644 src/framework/playground/PlayGround.Api/PlayGround.Api.csproj rename src/framework/{ => playground}/PlayGround.Api/PlayGround.Api.http (100%) create mode 100644 src/framework/playground/PlayGround.Api/Program.cs rename src/framework/{ => playground}/PlayGround.Api/Properties/launchSettings.json (54%) rename src/framework/{ => playground}/PlayGround.Api/appsettings.Development.json (100%) create mode 100644 src/framework/playground/PlayGround.Api/appsettings.json create mode 100644 src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.Designer.cs create mode 100644 src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs create mode 100644 src/framework/playground/migrations/PostgreSQL/Identity/IdentityDbContextModelSnapshot.cs create mode 100644 src/framework/playground/migrations/PostgreSQL/PostgreSQL.csproj create mode 100644 src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.Designer.cs create mode 100644 src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs create mode 100644 src/framework/playground/migrations/PostgreSQL/Tenant/TenantDbContextModelSnapshot.cs diff --git a/src/framework/Directory.Packages.props b/src/framework/Directory.Packages.props index bd4e4d234..db71b784a 100644 --- a/src/framework/Directory.Packages.props +++ b/src/framework/Directory.Packages.props @@ -40,6 +40,7 @@ + diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 325dd4974..5ba167f49 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -30,7 +30,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Packages.props = Directory.Packages.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayGround.Api", "PlayGround.Api\PlayGround.Api.csproj", "{BAC875BB-D97F-4E06-AFBB-5BB732582908}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PlayGround", "PlayGround", "{C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostgreSQL", "playground\migrations\PostgreSQL\PostgreSQL.csproj", "{EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayGround.Api", "playground\PlayGround.Api\PlayGround.Api.csproj", "{2527B9BA-2168-ED23-7E12-CF3C7C901279}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -74,10 +78,14 @@ Global {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.Build.0 = Debug|Any CPU {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.ActiveCfg = Release|Any CPU {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.Build.0 = Release|Any CPU - {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BAC875BB-D97F-4E06-AFBB-5BB732582908}.Release|Any CPU.Build.0 = Release|Any CPU + {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}.Release|Any CPU.Build.0 = Release|Any CPU + {2527B9BA-2168-ED23-7E12-CF3C7C901279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2527B9BA-2168-ED23-7E12-CF3C7C901279}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2527B9BA-2168-ED23-7E12-CF3C7C901279}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2527B9BA-2168-ED23-7E12-CF3C7C901279}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -89,9 +97,11 @@ Global {201606BA-48CE-42F0-B31F-596187F40B2F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {27806993-447E-9781-647B-06D3F4AC834A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {5324A0FF-DBB9-440C-80C2-4891EC719155} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2} = {C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B} + {2527B9BA-2168-ED23-7E12-CF3C7C901279} = {C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} SolutionGuid = {438A0F87-0F3E-43C4-A352-264E0C21F77B} + SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} EndGlobalSection EndGlobal diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs index ed027e12b..a0b2929cf 100644 --- a/src/framework/Infrastructure/Extensions.cs +++ b/src/framework/Infrastructure/Extensions.cs @@ -1,5 +1,4 @@ -using Asp.Versioning.Conventions; -using FluentValidation; +using FluentValidation; using FSH.Framework.Core; using FSH.Framework.Core.Origin; using FSH.Framework.Infrastructure.Caching; @@ -8,6 +7,8 @@ using FSH.Framework.Infrastructure.Jobs; using FSH.Framework.Infrastructure.Logging.Serilog; using FSH.Framework.Infrastructure.Mail; +using FSH.Framework.Infrastructure.Messaging.CQRS; +using FSH.Framework.Infrastructure.Messaging.Events; using FSH.Framework.Infrastructure.OpenApi; using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Infrastructure.RateLimit; @@ -26,6 +27,7 @@ public static class Extensions public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBuilder builder) { ArgumentNullException.ThrowIfNull(builder); + builder.Services.RegisterInMemoryEventBus(); builder.ConfigureSerilog(); builder.ConfigureDatabase(); builder.Services.AddCorsPolicy(builder.Configuration); @@ -39,7 +41,7 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui builder.Services.AddHealthChecks(); builder.Services.AddOptions().BindConfiguration(nameof(OriginOptions)); - // Define module assemblies + // Define framework assemblies var assemblies = new Assembly[] { typeof(FshCore).Assembly, @@ -49,6 +51,7 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui // Register validators builder.Services.AddValidatorsFromAssemblies(assemblies); + builder.Services.RegisterCommandAndQueryDispatchers(); builder.Services.ConfigureRateLimit(builder.Configuration); builder.Services.ConfigureSecurityHeaders(builder.Configuration); @@ -61,28 +64,24 @@ public static WebApplication UseFshFramework(this WebApplication app) app.UseSecurityHeaders(); app.UseExceptionHandler(); app.UseCorsPolicy(); - app.UseOpenApi(); + //app.UseOpenApi(); app.UseJobDashboard(app.Configuration); app.UseRouting(); app.UseStaticFiles(); + + var assetsPath = Path.Combine(Directory.GetCurrentDirectory(), "assets"); + if (!Directory.Exists(assetsPath)) + { + Directory.CreateDirectory(assetsPath); + } app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "assets")), RequestPath = new PathString("/assets") }); + app.UseAuthentication(); app.UseAuthorization(); - - // Register API versions - var versions = app.NewApiVersionSet() - .HasApiVersion(1) - .HasApiVersion(2) - .ReportApiVersions() - .Build(); - - // Map versioned endpoint - app.MapGroup("api/v{version:apiVersion}").WithApiVersionSet(versions); - return app; } } diff --git a/src/framework/Infrastructure/Messaging/CQRS/Extensions.cs b/src/framework/Infrastructure/Messaging/CQRS/Extensions.cs index f1779aef5..c53b04b72 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/Extensions.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Extensions.cs @@ -1,7 +1,7 @@ -using System.Reflection; -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Infrastructure.Messaging.CQRS.Validation; using Microsoft.Extensions.DependencyInjection; +using System.Reflection; namespace FSH.Framework.Infrastructure.Messaging.CQRS; public static class Extensions diff --git a/src/framework/Infrastructure/OpenApi/Extensions.cs b/src/framework/Infrastructure/OpenApi/Extensions.cs index df32e185f..ee11438f9 100644 --- a/src/framework/Infrastructure/OpenApi/Extensions.cs +++ b/src/framework/Infrastructure/OpenApi/Extensions.cs @@ -2,9 +2,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerUI; namespace FSH.Framework.Infrastructure.OpenApi; @@ -14,30 +11,30 @@ public static class Extensions public static IServiceCollection ConfigureOpenApi(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); - services.AddEndpointsApiExplorer(); - services.AddTransient, ConfigureSwaggerOptions>(); - services - .AddSwaggerGen(options => - { - options.OperationFilter(); - options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme - { - Type = SecuritySchemeType.Http, - Scheme = "bearer", - BearerFormat = "JWT", - Description = "JWT Authorization header using the Bearer scheme." - }); - options.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" } - }, - Array.Empty() - } - }); - }); + //services.AddEndpointsApiExplorer(); + //services.AddTransient, ConfigureSwaggerOptions>(); + //services + // .AddSwaggerGen(options => + // { + // options.OperationFilter(); + // options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme + // { + // Type = SecuritySchemeType.Http, + // Scheme = "bearer", + // BearerFormat = "JWT", + // Description = "JWT Authorization header using the Bearer scheme." + // }); + // options.AddSecurityRequirement(new OpenApiSecurityRequirement + // { + // { + // new OpenApiSecurityScheme + // { + // Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" } + // }, + // Array.Empty() + // } + // }); + // }); services .AddApiVersioning(options => { diff --git a/src/framework/Infrastructure/Persistence/Extensions.cs b/src/framework/Infrastructure/Persistence/Extensions.cs index c3220abc6..d86544817 100644 --- a/src/framework/Infrastructure/Persistence/Extensions.cs +++ b/src/framework/Infrastructure/Persistence/Extensions.cs @@ -10,13 +10,16 @@ namespace FSH.Framework.Infrastructure.Persistence; public static class Extensions { private static readonly ILogger Logger = Log.ForContext(typeof(Extensions)); - public static DbContextOptionsBuilder ConfigureDatabase(this DbContextOptionsBuilder builder, string dbProvider, string connectionString) + public static DbContextOptionsBuilder ConfigureDatabase(this DbContextOptionsBuilder builder, + string dbProvider, + string connectionString + ) { builder.ConfigureWarnings(warnings => warnings.Log(RelationalEventId.PendingModelChangesWarning)); return dbProvider.ToUpperInvariant() switch { DbProviders.PostgreSQL => builder.UseNpgsql(connectionString, e => - e.MigrationsAssembly("FSH.Starter.WebApi.Migrations.PostgreSQL")).EnableSensitiveDataLogging(), + e.MigrationsAssembly("FSH.PlayGround.Migrations.PostgreSQL")).EnableSensitiveDataLogging(), DbProviders.MSSQL => builder.UseSqlServer(connectionString, e => e.MigrationsAssembly("FSH.Starter.WebApi.Migrations.MSSQL")), _ => throw new InvalidOperationException($"DB Provider {dbProvider} is not supported."), diff --git a/src/framework/Modules/Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/AuditingModule.cs index 55c49c4e2..170db0252 100644 --- a/src/framework/Modules/Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/AuditingModule.cs @@ -1,5 +1,4 @@ using Asp.Versioning; -using FSH.Framework.Auditing.Features.v1.GetUserTrails; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Modules; using Microsoft.AspNetCore.Builder; @@ -32,7 +31,7 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) .WithOpenApi() .WithApiVersionSet(apiVersionSet); - GetUserTrailsEndpoint.Map(group); + //GetUserTrailsEndpoint.Map(group); return endpoints; } diff --git a/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs b/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs new file mode 100644 index 000000000..34ff69712 --- /dev/null +++ b/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization.Policy; +using Microsoft.AspNetCore.Http; + +namespace FSH.Framework.Identity.Authorization; +public class PathAwareAuthorizationHandler : IAuthorizationMiddlewareResultHandler +{ + private readonly AuthorizationMiddlewareResultHandler _fallback = new(); + + public async Task HandleAsync( + RequestDelegate next, + HttpContext context, + AuthorizationPolicy policy, + PolicyAuthorizationResult authorizeResult) + { + var path = context.Request.Path; + + if (path.StartsWithSegments("/scalar") || path.StartsWithSegments("/openapi")) + { + // ✅ Respect routing + continue the pipeline + var endpoint = context.GetEndpoint(); + if (endpoint != null) + { + await next(context); + return; + } + + // If no endpoint is found, return 404 explicitly + context.Response.StatusCode = StatusCodes.Status404NotFound; + await context.Response.WriteAsync("Endpoint not found."); + return; + } + + await _fallback.HandleAsync(next, context, policy, authorizeResult); + } +} + diff --git a/src/framework/Modules/Identity/IdentityModule.cs b/src/framework/Modules/Identity/IdentityModule.cs index 732f769ab..6144a65ef 100644 --- a/src/framework/Modules/Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/IdentityModule.cs @@ -1,5 +1,7 @@ -using FSH.Framework.Core.ExecutionContext; +using Asp.Versioning; +using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Core.Persistence; +using FSH.Framework.Identity.Authorization; using FSH.Framework.Identity.Contracts; using FSH.Framework.Identity.Core.Roles; using FSH.Framework.Identity.Core.Tokens; @@ -10,12 +12,18 @@ using FSH.Framework.Identity.Infrastructure.Users; using FSH.Framework.Identity.v1.Tokens.TokenGeneration; using FSH.Framework.Infrastructure.Auth; +using FSH.Framework.Infrastructure.Auth.Jwt; using FSH.Framework.Infrastructure.Identity.Roles; using FSH.Framework.Infrastructure.Identity.Users.Services; +using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Persistence; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using System.Reflection; namespace FSH.Framework.Identity; public static class IdentityModule @@ -23,7 +31,16 @@ public static class IdentityModule public static IServiceCollection RegisterIdentityModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); + + var assemblies = new Assembly[] + { + typeof(IdentityModule).Assembly, + typeof(IdentityModuleConstants).Assembly + }; + + services.RegisterCommandAndQueryHandlers(assemblies); services.AddScoped(); + services.AddSingleton(); services.AddScoped(); services.AddScoped(); services.AddScoped(sp => (ICurrentUserInitializer)sp.GetRequiredService()); @@ -42,12 +59,24 @@ public static IServiceCollection RegisterIdentityModule(this IServiceCollection }) .AddEntityFrameworkStores() .AddDefaultTokenProviders(); + services.ConfigureJwtAuth(); return services; } public static IEndpointRouteBuilder MapIdentityEndpoints(this IEndpointRouteBuilder endpoints) { - TokenGenerationEndpoint.Map(endpoints); + var apiVersionSet = endpoints.NewApiVersionSet() + .HasApiVersion(new ApiVersion(1)) + .ReportApiVersions() + .Build(); + + var group = endpoints + .MapGroup("api/v{version:apiVersion}/identity") + .WithTags("Identity") + .WithOpenApi() + .WithApiVersionSet(apiVersionSet); + + TokenGenerationEndpoint.Map(group); return endpoints; } } diff --git a/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs index dd7d8ccf8..bed060b3a 100644 --- a/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs @@ -13,7 +13,7 @@ public static class UpdateRolePermissionsEndpoint public static RouteHandlerBuilder MapUpdateRolePermissionsEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapPut("/{id}/permissions", async ( - UpdatePermissionsCommand request, + [FromBody] UpdatePermissionsCommand request, IRoleService roleService, string id, [FromServices] IValidator validator) => diff --git a/src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs b/src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs index bbac696cb..eb48a66f4 100644 --- a/src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs @@ -3,6 +3,7 @@ using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Infrastructure.Identity.Roles.Endpoints; @@ -11,7 +12,7 @@ public static class CreateOrUpdateRoleEndpoint { public static RouteHandlerBuilder MapCreateOrUpdateRoleEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/", async (UpsertRoleCommand request, IRoleService roleService) => + return endpoints.MapPost("/", async ([FromBody] UpsertRoleCommand request, IRoleService roleService) => { return await roleService.CreateOrUpdateRoleAsync(request.Id, request.Name, request.Description); }) diff --git a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs index d7106bb93..824a67912 100644 --- a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs @@ -2,6 +2,7 @@ using FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; @@ -9,10 +10,10 @@ public static class TokenGenerationEndpoint { internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/", async ( - TokenGenerationCommand command, + return endpoints.MapPost("/tokens", async ( + [FromBody] TokenGenerationCommand command, string tenant, - ICommandDispatcher dispatcher, + [FromServices] ICommandDispatcher dispatcher, HttpContext context, CancellationToken cancellationToken) => { diff --git a/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs index 3b5036d99..4672d44d2 100644 --- a/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs @@ -16,7 +16,7 @@ public static class ForgotPasswordEndpoint { internal static RouteHandlerBuilder MapForgotPasswordEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/forgot-password", async (HttpRequest request, [FromHeader(Name = TenantConstants.Identifier)] string tenant, ForgotPasswordCommand command, IOptions settings, IValidator validator, IUserService userService, CancellationToken cancellationToken) => + return endpoints.MapPost("/forgot-password", async (HttpRequest request, [FromHeader(Name = TenantConstants.Identifier)] string tenant, [FromBody] ForgotPasswordCommand command, IOptions settings, IValidator validator, IUserService userService, CancellationToken cancellationToken) => { ValidationResult result = await validator.ValidateAsync(command, cancellationToken); if (!result.IsValid) diff --git a/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs index d0e63812a..1c05cefdc 100644 --- a/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs @@ -15,7 +15,7 @@ public static class ResetPasswordEndpoint internal static RouteHandlerBuilder MapResetPasswordEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/reset-password", - async (ResetPasswordCommand command, + async ([FromBody] ResetPasswordCommand command, [FromHeader(Name = TenantConstants.Identifier)] string tenant, IValidator validator, IUserService userService, CancellationToken cancellationToken) => diff --git a/src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs b/src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs index a2f77305d..24b442f02 100644 --- a/src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs @@ -13,8 +13,8 @@ public static class ToggleUserStatusEndpoint internal static RouteHandlerBuilder ToggleUserStatusEndpointEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/{id:guid}/toggle-status", async ( - string id, - ToggleUserStatusCommand command, + [FromQuery] string id, + [FromBody] ToggleUserStatusCommand command, [FromServices] IUserService userService, CancellationToken cancellationToken) => { diff --git a/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs index 462a8c2db..60384819b 100644 --- a/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs +++ b/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs @@ -30,7 +30,7 @@ public UpdateUserCommandValidator() When(x => x.Image is not null, () => { RuleFor(x => x.Image!) - .SetValidator(new FileUploadRequestValidator(FileType.Image)); + .SetValidator(new UserImageValidator(FileType.Image)); }); // Prevent deleting and uploading image at the same time diff --git a/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs b/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs index ddd0d2379..2d7601a5b 100644 --- a/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs @@ -5,6 +5,7 @@ using FSH.Framework.Shared.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using System.Security.Claims; @@ -13,7 +14,7 @@ public static class UpdateUserEndpoint { internal static RouteHandlerBuilder MapUpdateUserEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPut("/profile", (UpdateUserCommand request, ClaimsPrincipal user, IUserService service) => + return endpoints.MapPut("/profile", ([FromBody] UpdateUserCommand request, ClaimsPrincipal user, IUserService service) => { if (user.GetUserId() is not { } userId || string.IsNullOrEmpty(userId)) { diff --git a/src/framework/Core/Storage/FileUploadRequestValidator.cs b/src/framework/Modules/Identity/v1/Users/UserImageValidator.cs similarity index 74% rename from src/framework/Core/Storage/FileUploadRequestValidator.cs rename to src/framework/Modules/Identity/v1/Users/UserImageValidator.cs index 6fcd8381b..8527e998f 100644 --- a/src/framework/Core/Storage/FileUploadRequestValidator.cs +++ b/src/framework/Modules/Identity/v1/Users/UserImageValidator.cs @@ -1,10 +1,10 @@ using FluentValidation; +using FSH.Framework.Core.Storage; -namespace FSH.Framework.Core.Storage; - -public class FileUploadRequestValidator : AbstractValidator +namespace FSH.Framework.Identity.v1.Users; +public class UserImageValidator : AbstractValidator { - public FileUploadRequestValidator(FileType fileType) + public UserImageValidator(FileType fileType) { var rules = FileTypeMetadata.GetRules(fileType); diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs index 781a1a2b7..265c47f4e 100644 --- a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs @@ -3,6 +3,7 @@ using FSH.Framework.Tenant.Contracts.v1.CreateTenant; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Tenant.Features.v1.CreateTenant; @@ -10,7 +11,9 @@ public static class CreateTenantEndpoint { internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/", async (ICommandDispatcher dispatcher, CreateTenantCommand command) + return endpoints.MapPost("/", async ( + [FromBody] CreateTenantCommand command, + [FromServices] ICommandDispatcher dispatcher) => await dispatcher.SendAsync(command)) .WithName(nameof(CreateTenantEndpoint)) .WithSummary("activate tenant") diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs index 627d58d71..f38bf5a61 100644 --- a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs @@ -3,6 +3,7 @@ using FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Tenant.Features.v1.UpgradeTenant; @@ -10,7 +11,7 @@ public static class UpgradeTenantEndpoint { internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/upgrade", (UpgradeTenantCommand command, ICommandDispatcher dispatcher) + return endpoints.MapPost("/upgrade", ([FromBody] UpgradeTenantCommand command, ICommandDispatcher dispatcher) => dispatcher.SendAsync(command)) .WithName(nameof(UpgradeTenantEndpoint)) .WithSummary("upgrade tenant subscription") diff --git a/src/framework/Modules/Tenant/TenantModule.cs b/src/framework/Modules/Tenant/TenantModule.cs index 3d1f0210c..2aa3f523b 100644 --- a/src/framework/Modules/Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/TenantModule.cs @@ -9,12 +9,7 @@ using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Data; -using FSH.Framework.Tenant.Features.v1.ActivateTenant; using FSH.Framework.Tenant.Features.v1.CreateTenant; -using FSH.Framework.Tenant.Features.v1.DisableTenant; -using FSH.Framework.Tenant.Features.v1.GetTenantById; -using FSH.Framework.Tenant.Features.v1.GetTenants; -using FSH.Framework.Tenant.Features.v1.UpgradeTenant; using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; @@ -159,12 +154,12 @@ public static IEndpointRouteBuilder MapTenantEndpoints(this IEndpointRouteBuilde .WithOpenApi() .WithApiVersionSet(apiVersionSet); - CreateTenantEndpoint.Map(group); - DisableTenantEndpoint.Map(group); - GetTenantByIdEndpoint.Map(group); - GetTenantsEndpoint.Map(group); - UpgradeTenantEndpoint.Map(group); - ActivateTenantEndpoint.Map(group); + CreateTenantEndpoint.Map(group).AllowAnonymous(); + //DisableTenantEndpoint.Map(group); + //GetTenantByIdEndpoint.Map(group); + //GetTenantsEndpoint.Map(group); + //UpgradeTenantEndpoint.Map(group); + //ActivateTenantEndpoint.Map(group); return endpoints; } diff --git a/src/framework/PlayGround.Api/PlayGround.Api.csproj b/src/framework/PlayGround.Api/PlayGround.Api.csproj deleted file mode 100644 index 203645a61..000000000 --- a/src/framework/PlayGround.Api/PlayGround.Api.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net9.0 - enable - enable - - - - - - - diff --git a/src/framework/PlayGround.Api/Program.cs b/src/framework/PlayGround.Api/Program.cs deleted file mode 100644 index ad8699de7..000000000 --- a/src/framework/PlayGround.Api/Program.cs +++ /dev/null @@ -1,41 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); - -// Add services to the container. -// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi -builder.Services.AddOpenApi(); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.MapOpenApi(); -} - -app.UseHttpsRedirection(); - -var summaries = new[] -{ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; - -app.MapGet("/weatherforecast", () => -{ - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; -}) -.WithName("GetWeatherForecast"); - -app.Run(); - -internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) -{ - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); -} diff --git a/src/framework/PlayGround.Api/appsettings.json b/src/framework/PlayGround.Api/appsettings.json deleted file mode 100644 index 10f68b8c8..000000000 --- a/src/framework/PlayGround.Api/appsettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*" -} diff --git a/src/framework/playground/PlayGround.Api/PlayGround.Api.csproj b/src/framework/playground/PlayGround.Api/PlayGround.Api.csproj new file mode 100644 index 000000000..a893a2000 --- /dev/null +++ b/src/framework/playground/PlayGround.Api/PlayGround.Api.csproj @@ -0,0 +1,30 @@ + + + FSH.PlayGround.Api + FSH.PlayGround.Api + + + net9.0 + enable + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/src/framework/PlayGround.Api/PlayGround.Api.http b/src/framework/playground/PlayGround.Api/PlayGround.Api.http similarity index 100% rename from src/framework/PlayGround.Api/PlayGround.Api.http rename to src/framework/playground/PlayGround.Api/PlayGround.Api.http diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs new file mode 100644 index 000000000..951a151e6 --- /dev/null +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -0,0 +1,24 @@ +using FSH.Framework.Identity; +using FSH.Framework.Infrastructure; +using FSH.Framework.Tenant; +using Scalar.AspNetCore; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddOpenApi(); + +builder.ConfigureFshFramework(); +builder.Services.RegisterTenantModuleServices(); +builder.Services.RegisterIdentityModule(); + +var app = builder.Build(); +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); + app.MapScalarApiReference(); +} +app.UseTenantModule(); +app.MapIdentityEndpoints(); +app.UseFshFramework(); +app.MapGet("/", () => "Gello"); +app.UseHttpsRedirection(); +await app.RunAsync(); \ No newline at end of file diff --git a/src/framework/PlayGround.Api/Properties/launchSettings.json b/src/framework/playground/PlayGround.Api/Properties/launchSettings.json similarity index 54% rename from src/framework/PlayGround.Api/Properties/launchSettings.json rename to src/framework/playground/PlayGround.Api/Properties/launchSettings.json index 980b6b394..30930a61d 100644 --- a/src/framework/PlayGround.Api/Properties/launchSettings.json +++ b/src/framework/playground/PlayGround.Api/Properties/launchSettings.json @@ -1,19 +1,11 @@ { "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": false, - "applicationUrl": "http://localhost:5153", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "https": { "commandName": "Project", "dotnetRunMessages": true, - "launchBrowser": false, + "launchBrowser": true, + "launchUrl": "scalar/v1", "applicationUrl": "https://localhost:7044;http://localhost:5153", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" diff --git a/src/framework/PlayGround.Api/appsettings.Development.json b/src/framework/playground/PlayGround.Api/appsettings.Development.json similarity index 100% rename from src/framework/PlayGround.Api/appsettings.Development.json rename to src/framework/playground/PlayGround.Api/appsettings.Development.json diff --git a/src/framework/playground/PlayGround.Api/appsettings.json b/src/framework/playground/PlayGround.Api/appsettings.json new file mode 100644 index 000000000..1117a1454 --- /dev/null +++ b/src/framework/playground/PlayGround.Api/appsettings.json @@ -0,0 +1,68 @@ +{ + "DatabaseOptions": { + "Provider": "postgresql", + "ConnectionString": "Server=192.168.1.110;Database=phoenix;User Id=postgres;Password=password" + }, + "OriginOptions": { + "OriginUrl": "https://localhost:7000" + }, + "CacheOptions": { + "Redis": "" + }, + "HangfireOptions": { + "Username": "admin", + "Password": "Secure1234!Me", + "Route": "/jobs" + }, + "JwtOptions": { + "Key": "QsJbczCNysv/5SGh+U7sxedX8C07TPQPBdsnSDKZ/aE=", + "TokenExpirationInMinutes": 60, + "RefreshTokenExpirationInDays": 7 + }, + "MailOptions": { + "From": "mukesh@fullstackhero.net", + "Host": "smtp.ethereal.email", + "Port": 587, + "UserName": "ruth.ruecker@ethereal.email", + "Password": "wygzuX6kpcK6AfDJcd", + "DisplayName": "Mukesh Murugan" + }, + "CorsOptions": { + "AllowedOrigins": [ + "https://localhost:7100", + "http://localhost:7100", + "http://localhost:5010" + ] + }, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console" + ], + "MinimumLevel": { + "Default": "Debug" + }, + "WriteTo": [ + { + "Name": "Console" + } + ] + }, + "RateLimitOptions": { + "EnableRateLimiting": false, + "PermitLimit": 5, + "WindowInSeconds": 10, + "RejectionStatusCode": 429 + }, + "SecurityHeaderOptions": { + "Enable": true, + "Headers": { + "XContentTypeOptions": "nosniff", + "ReferrerPolicy": "no-referrer", + "XXSSProtection": "1; mode=block", + "XFrameOptions": "DENY", + "ContentSecurityPolicy": "block-all-mixed-content; style-src 'self' 'unsafe-inline'; font-src 'self'; form-action 'self'; frame-ancestors 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline'", + "PermissionsPolicy": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()", + "StrictTransportSecurity": "max-age=31536000" + } + } +} \ No newline at end of file diff --git a/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.Designer.cs b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.Designer.cs new file mode 100644 index 000000000..85fb2de91 --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.Designer.cs @@ -0,0 +1,357 @@ +// +using System; +using FSH.Framework.Identity.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Identity +{ + [DbContext(typeof(IdentityDbContext))] + [Migration("20250416110641_Add Identity Schema")] + partial class AddIdentitySchema + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FSH.Framework.Identity.Infrastructure.Roles.FshRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName", "TenantId") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Roles", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("FSH.Framework.Identity.Infrastructure.Users.FshUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("ImageUrl") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ObjectId") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("RefreshToken") + .HasColumnType("text"); + + b.Property("RefreshTokenExpiryTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("Users", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("FSH.Framework.Identity.v1.RoleClaims.FshRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("CreatedBy") + .HasColumnType("text"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("FSH.Framework.Identity.v1.RoleClaims.FshRoleClaim", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Roles.FshRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Roles.FshRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs new file mode 100644 index 000000000..52fc4074d --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs @@ -0,0 +1,268 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Identity; + +/// +public partial class AddIdentitySchema : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "identity"); + + migrationBuilder.CreateTable( + name: "Roles", + schema: "identity", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Description = table.Column(type: "text", nullable: true), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Roles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Users", + schema: "identity", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + FirstName = table.Column(type: "text", nullable: true), + LastName = table.Column(type: "text", nullable: true), + ImageUrl = table.Column(type: "text", nullable: true), + IsActive = table.Column(type: "boolean", nullable: false), + RefreshToken = table.Column(type: "text", nullable: true), + RefreshTokenExpiryTime = table.Column(type: "timestamp with time zone", nullable: false), + ObjectId = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + UserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "boolean", nullable: false), + PasswordHash = table.Column(type: "text", nullable: true), + SecurityStamp = table.Column(type: "text", nullable: true), + ConcurrencyStamp = table.Column(type: "text", nullable: true), + PhoneNumber = table.Column(type: "text", nullable: true), + PhoneNumberConfirmed = table.Column(type: "boolean", nullable: false), + TwoFactorEnabled = table.Column(type: "boolean", nullable: false), + LockoutEnd = table.Column(type: "timestamp with time zone", nullable: true), + LockoutEnabled = table.Column(type: "boolean", nullable: false), + AccessFailedCount = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "RoleClaims", + schema: "identity", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CreatedBy = table.Column(type: "text", nullable: true), + CreatedOn = table.Column(type: "timestamp with time zone", nullable: false), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + RoleId = table.Column(type: "text", nullable: false), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_RoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_RoleClaims_Roles_RoleId", + column: x => x.RoleId, + principalSchema: "identity", + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserClaims", + schema: "identity", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "text", nullable: false), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserClaims", x => x.Id); + table.ForeignKey( + name: "FK_UserClaims_Users_UserId", + column: x => x.UserId, + principalSchema: "identity", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserLogins", + schema: "identity", + columns: table => new + { + LoginProvider = table.Column(type: "text", nullable: false), + ProviderKey = table.Column(type: "text", nullable: false), + ProviderDisplayName = table.Column(type: "text", nullable: true), + UserId = table.Column(type: "text", nullable: false), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_UserLogins_Users_UserId", + column: x => x.UserId, + principalSchema: "identity", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserRoles", + schema: "identity", + columns: table => new + { + UserId = table.Column(type: "text", nullable: false), + RoleId = table.Column(type: "text", nullable: false), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_UserRoles_Roles_RoleId", + column: x => x.RoleId, + principalSchema: "identity", + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_UserRoles_Users_UserId", + column: x => x.UserId, + principalSchema: "identity", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserTokens", + schema: "identity", + columns: table => new + { + UserId = table.Column(type: "text", nullable: false), + LoginProvider = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Value = table.Column(type: "text", nullable: true), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_UserTokens_Users_UserId", + column: x => x.UserId, + principalSchema: "identity", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_RoleClaims_RoleId", + schema: "identity", + table: "RoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + schema: "identity", + table: "Roles", + columns: new[] { "NormalizedName", "TenantId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_UserClaims_UserId", + schema: "identity", + table: "UserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_UserLogins_UserId", + schema: "identity", + table: "UserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_UserRoles_RoleId", + schema: "identity", + table: "UserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + schema: "identity", + table: "Users", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + schema: "identity", + table: "Users", + column: "NormalizedUserName", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RoleClaims", + schema: "identity"); + + migrationBuilder.DropTable( + name: "UserClaims", + schema: "identity"); + + migrationBuilder.DropTable( + name: "UserLogins", + schema: "identity"); + + migrationBuilder.DropTable( + name: "UserRoles", + schema: "identity"); + + migrationBuilder.DropTable( + name: "UserTokens", + schema: "identity"); + + migrationBuilder.DropTable( + name: "Roles", + schema: "identity"); + + migrationBuilder.DropTable( + name: "Users", + schema: "identity"); + } +} diff --git a/src/framework/playground/migrations/PostgreSQL/Identity/IdentityDbContextModelSnapshot.cs b/src/framework/playground/migrations/PostgreSQL/Identity/IdentityDbContextModelSnapshot.cs new file mode 100644 index 000000000..e02243f20 --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Identity/IdentityDbContextModelSnapshot.cs @@ -0,0 +1,354 @@ +// +using System; +using FSH.Framework.Identity.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Identity +{ + [DbContext(typeof(IdentityDbContext))] + partial class IdentityDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FSH.Framework.Identity.Infrastructure.Roles.FshRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName", "TenantId") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("Roles", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("FSH.Framework.Identity.Infrastructure.Users.FshUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("ImageUrl") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ObjectId") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("RefreshToken") + .HasColumnType("text"); + + b.Property("RefreshTokenExpiryTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("Users", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("FSH.Framework.Identity.v1.RoleClaims.FshRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("CreatedBy") + .HasColumnType("text"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", "identity"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + + modelBuilder.Entity("FSH.Framework.Identity.v1.RoleClaims.FshRoleClaim", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Roles.FshRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Roles.FshRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("FSH.Framework.Identity.Infrastructure.Users.FshUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/framework/playground/migrations/PostgreSQL/PostgreSQL.csproj b/src/framework/playground/migrations/PostgreSQL/PostgreSQL.csproj new file mode 100644 index 000000000..f81aede8e --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/PostgreSQL.csproj @@ -0,0 +1,19 @@ + + + FSH.PlayGround.Migrations.PostgreSQL + FSH.PlayGround.Migrations.PostgreSQL + + + net9.0 + enable + enable + + + + + + + + + + diff --git a/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.Designer.cs b/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.Designer.cs new file mode 100644 index 000000000..8417128d0 --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.Designer.cs @@ -0,0 +1,69 @@ +// +using System; +using FSH.Framework.Tenant.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Tenant +{ + [DbContext(typeof(TenantDbContext))] + [Migration("20250416110812_Add Tenant Schema")] + partial class AddTenantSchema + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FSH.Framework.Shared.Multitenancy.FshTenantInfo", b => + { + b.Property("Id") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("AdminEmail") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConnectionString") + .IsRequired() + .HasColumnType("text"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Issuer") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ValidUpto") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("Identifier") + .IsUnique(); + + b.ToTable("Tenants", "tenant"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs b/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs new file mode 100644 index 000000000..77e4945ec --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Tenant; + +/// +public partial class AddTenantSchema : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "tenant"); + + migrationBuilder.CreateTable( + name: "Tenants", + schema: "tenant", + columns: table => new + { + Id = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + Identifier = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + ConnectionString = table.Column(type: "text", nullable: false), + AdminEmail = table.Column(type: "text", nullable: false), + IsActive = table.Column(type: "boolean", nullable: false), + ValidUpto = table.Column(type: "timestamp without time zone", nullable: false), + Issuer = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Tenants", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Tenants_Identifier", + schema: "tenant", + table: "Tenants", + column: "Identifier", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Tenants", + schema: "tenant"); + } +} diff --git a/src/framework/playground/migrations/PostgreSQL/Tenant/TenantDbContextModelSnapshot.cs b/src/framework/playground/migrations/PostgreSQL/Tenant/TenantDbContextModelSnapshot.cs new file mode 100644 index 000000000..d1ecf509b --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Tenant/TenantDbContextModelSnapshot.cs @@ -0,0 +1,66 @@ +// +using System; +using FSH.Framework.Tenant.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Tenant +{ + [DbContext(typeof(TenantDbContext))] + partial class TenantDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FSH.Framework.Shared.Multitenancy.FshTenantInfo", b => + { + b.Property("Id") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("AdminEmail") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConnectionString") + .IsRequired() + .HasColumnType("text"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Issuer") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ValidUpto") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("Identifier") + .IsUnique(); + + b.ToTable("Tenants", "tenant"); + }); +#pragma warning restore 612, 618 + } + } +} From 57954f525bc5b588cfb1d981906a5c4e8849241b Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 16 Apr 2025 23:34:02 +0530 Subject: [PATCH 34/54] cleanup --- src/framework/Infrastructure/Extensions.cs | 7 ++++--- .../Infrastructure/Messaging/CQRS/CommandDispatcher.cs | 1 - .../v1/Tokens/TokenGeneration/TokenGenerationCommand.cs | 2 +- src/framework/Modules/Identity/IdentityModule.cs | 9 +-------- .../TokenGeneration/TokenGenerationCommandHandler.cs | 6 ++++-- src/framework/playground/PlayGround.Api/Program.cs | 1 - 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs index a0b2929cf..d31bc50a7 100644 --- a/src/framework/Infrastructure/Extensions.cs +++ b/src/framework/Infrastructure/Extensions.cs @@ -27,6 +27,7 @@ public static class Extensions public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBuilder builder) { ArgumentNullException.ThrowIfNull(builder); + builder.Services.AddHttpContextAccessor(); builder.Services.RegisterInMemoryEventBus(); builder.ConfigureSerilog(); builder.ConfigureDatabase(); @@ -69,15 +70,15 @@ public static WebApplication UseFshFramework(this WebApplication app) app.UseRouting(); app.UseStaticFiles(); - var assetsPath = Path.Combine(Directory.GetCurrentDirectory(), "assets"); + var assetsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"); if (!Directory.Exists(assetsPath)) { Directory.CreateDirectory(assetsPath); } app.UseStaticFiles(new StaticFileOptions() { - FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "assets")), - RequestPath = new PathString("/assets") + FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")), + RequestPath = new PathString("/wwwroot") }); app.UseAuthentication(); diff --git a/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs b/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs index ad59b5ba5..3c86705c8 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs @@ -12,7 +12,6 @@ public CommandDispatcher(IServiceProvider serviceProvider) => public Task SendAsync(ICommand command, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(command); - var handlerType = typeof(ICommandHandler<,>).MakeGenericType(command.GetType(), typeof(TResponse)); dynamic handler = _serviceProvider.GetRequiredService(handlerType); diff --git a/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs index 6200040a2..82621b65e 100644 --- a/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs +++ b/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs @@ -1,5 +1,5 @@ using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; -public record TokenGenerationCommand(string Email, string Password, string IpAddress) +public record TokenGenerationCommand(string Email, string Password) : ICommand; diff --git a/src/framework/Modules/Identity/IdentityModule.cs b/src/framework/Modules/Identity/IdentityModule.cs index 6144a65ef..6e526b33d 100644 --- a/src/framework/Modules/Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/IdentityModule.cs @@ -31,14 +31,7 @@ public static class IdentityModule public static IServiceCollection RegisterIdentityModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); - - var assemblies = new Assembly[] - { - typeof(IdentityModule).Assembly, - typeof(IdentityModuleConstants).Assembly - }; - - services.RegisterCommandAndQueryHandlers(assemblies); + services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); services.AddScoped(); services.AddSingleton(); services.AddScoped(); diff --git a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs index 0d40c70ec..4ca8738c4 100644 --- a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs +++ b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs @@ -5,12 +5,14 @@ using Microsoft.AspNetCore.Http; namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; -internal class TokenGenerationCommandHandler(ITokenService tokenService, HttpContext context) +public class TokenGenerationCommandHandler( + ITokenService tokenService, + IHttpContextAccessor contextAccessor) : ICommandHandler { public async Task HandleAsync(TokenGenerationCommand command, CancellationToken cancellationToken = default) { - string ip = context.GetIpAddress(); + string? ip = contextAccessor.HttpContext?.GetIpAddress() ?? "unknown"; var token = await tokenService.GenerateTokenAsync(command.Email, command.Password, ip, cancellationToken); return new TokenGenerationCommandResponse(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); } diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index 951a151e6..4fe782bbf 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -5,7 +5,6 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddOpenApi(); - builder.ConfigureFshFramework(); builder.Services.RegisterTenantModuleServices(); builder.Services.RegisterIdentityModule(); From 17e3014a940f3187e86032ad1328c85497bcf5d1 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 17 Apr 2025 12:43:17 +0530 Subject: [PATCH 35/54] cleanup --- src/framework/Infrastructure/Extensions.cs | 6 ++++-- src/framework/Infrastructure/Jobs/Extensions.cs | 2 +- .../Authorization/PathAwareAuthorizationHandler.cs | 9 +++++++-- src/framework/Modules/Identity/IdentityModule.cs | 2 +- .../Identity/Options/ConfigureJwtBearerOptions.cs | 7 ++++++- src/framework/Modules/Tenant/TenantModule.cs | 4 ++-- src/framework/playground/PlayGround.Api/Program.cs | 12 +++++++----- 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs index d31bc50a7..5a8ec9c1e 100644 --- a/src/framework/Infrastructure/Extensions.cs +++ b/src/framework/Infrastructure/Extensions.cs @@ -28,7 +28,6 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui { ArgumentNullException.ThrowIfNull(builder); builder.Services.AddHttpContextAccessor(); - builder.Services.RegisterInMemoryEventBus(); builder.ConfigureSerilog(); builder.ConfigureDatabase(); builder.Services.AddCorsPolicy(builder.Configuration); @@ -52,7 +51,10 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui // Register validators builder.Services.AddValidatorsFromAssemblies(assemblies); + // register messaging services builder.Services.RegisterCommandAndQueryDispatchers(); + builder.Services.RegisterInMemoryEventBus(); + builder.Services.ConfigureRateLimit(builder.Configuration); builder.Services.ConfigureSecurityHeaders(builder.Configuration); @@ -78,7 +80,7 @@ public static WebApplication UseFshFramework(this WebApplication app) app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")), - RequestPath = new PathString("/wwwroot") + RequestPath = new PathString("/wwwroot"), }); app.UseAuthentication(); diff --git a/src/framework/Infrastructure/Jobs/Extensions.cs b/src/framework/Infrastructure/Jobs/Extensions.cs index 2e8197400..2388ac729 100644 --- a/src/framework/Infrastructure/Jobs/Extensions.cs +++ b/src/framework/Infrastructure/Jobs/Extensions.cs @@ -20,7 +20,7 @@ internal static IServiceCollection ConfigureJobs(this IServiceCollection service services.AddHangfireServer(o => { o.HeartbeatInterval = TimeSpan.FromSeconds(30); - o.Queues = new string[] { "default", "email" }; + o.Queues = ["default", "email"]; o.WorkerCount = 5; o.SchedulePollingInterval = TimeSpan.FromSeconds(30); }); diff --git a/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs b/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs index 34ff69712..7fc3650f8 100644 --- a/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs +++ b/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs @@ -14,8 +14,13 @@ public async Task HandleAsync( PolicyAuthorizationResult authorizeResult) { var path = context.Request.Path; - - if (path.StartsWithSegments("/scalar") || path.StartsWithSegments("/openapi")) + var allowedPaths = new[] + { + new PathString("/scalar"), + new PathString("/openapi"), + new PathString("/favicon.ico") + }; + if (allowedPaths.Any(p => path.StartsWithSegments(p, StringComparison.OrdinalIgnoreCase))) { // ✅ Respect routing + continue the pipeline var endpoint = context.GetEndpoint(); diff --git a/src/framework/Modules/Identity/IdentityModule.cs b/src/framework/Modules/Identity/IdentityModule.cs index 6e526b33d..193a938e3 100644 --- a/src/framework/Modules/Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/IdentityModule.cs @@ -28,7 +28,7 @@ namespace FSH.Framework.Identity; public static class IdentityModule { - public static IServiceCollection RegisterIdentityModule(this IServiceCollection services) + public static IServiceCollection ConfigureIdentityModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); diff --git a/src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs b/src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs index 7381ed077..71be89e79 100644 --- a/src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs +++ b/src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs @@ -48,9 +48,14 @@ public void Configure(string? name, JwtBearerOptions options) OnChallenge = context => { context.HandleResponse(); + if (!context.Response.HasStarted) { - throw new UnauthorizedException(); + var path = context.HttpContext.Request.Path; + var method = context.HttpContext.Request.Method; + + // You can include more details if needed like headers, etc. + throw new UnauthorizedException($"Unauthorized access to {method} {path}"); } return Task.CompletedTask; diff --git a/src/framework/Modules/Tenant/TenantModule.cs b/src/framework/Modules/Tenant/TenantModule.cs index 2aa3f523b..4d0d131e6 100644 --- a/src/framework/Modules/Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/TenantModule.cs @@ -22,7 +22,7 @@ namespace FSH.Framework.Tenant; public static class TenantModule { - public static IServiceCollection RegisterTenantModuleServices(this IServiceCollection services) + public static IServiceCollection ConfigureTenantModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); @@ -63,7 +63,7 @@ public static IServiceCollection RegisterTenantModuleServices(this IServiceColle services.AddScoped(); return services; } - public static WebApplication UseTenantModule(this WebApplication app) + public static WebApplication UseFshMultiTenancy(this WebApplication app) { ArgumentNullException.ThrowIfNull(app); app.UseMultiTenant(); diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index 4fe782bbf..bc440df3d 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -6,8 +6,8 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddOpenApi(); builder.ConfigureFshFramework(); -builder.Services.RegisterTenantModuleServices(); -builder.Services.RegisterIdentityModule(); +builder.Services.ConfigureTenantModule(); +builder.Services.ConfigureIdentityModule(); var app = builder.Build(); if (app.Environment.IsDevelopment()) @@ -15,9 +15,11 @@ app.MapOpenApi(); app.MapScalarApiReference(); } -app.UseTenantModule(); -app.MapIdentityEndpoints(); + +app.UseFshMultiTenancy(); app.UseFshFramework(); -app.MapGet("/", () => "Gello"); + +app.MapIdentityEndpoints(); + app.UseHttpsRedirection(); await app.RunAsync(); \ No newline at end of file From a744e2a5e46ee5a916d6917a57ae124891821232 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 17 Apr 2025 17:25:53 +0530 Subject: [PATCH 36/54] fix validation pipeline --- .../CQRS/Validation/CommandValidation.cs | 11 ++- .../CQRS/Validation/QueryValidation.cs | 11 ++- .../CQRS/Validation/ValidationHelper.cs | 14 ++-- .../Infrastructure/OpenApi/Extensions.cs | 2 +- .../Modules/Auditing/AuditingModule.cs | 20 +++-- .../v1/GetUserTrails/GetUserTrailsEndpoint.cs | 3 +- .../TokenGeneration/TokenGenerationCommand.cs | 4 +- .../Modules/Identity/IdentityModule.cs | 20 ++++- .../TokenGenerationCommandValidator.cs | 2 +- .../TokenGenerationEndpoint.cs | 3 +- .../ActivateTenant/ActivateTenantEndpoint.cs | 7 +- .../playground/PlayGround.Api/Program.cs | 6 +- ...0417072044_Add Auditing Schema.Designer.cs | 80 +++++++++++++++++++ .../20250417072044_Add Auditing Schema.cs | 46 +++++++++++ .../AuditingDbContextModelSnapshot.cs | 77 ++++++++++++++++++ 15 files changed, 268 insertions(+), 38 deletions(-) create mode 100644 src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.Designer.cs create mode 100644 src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs create mode 100644 src/framework/playground/migrations/PostgreSQL/Auditing/AuditingDbContextModelSnapshot.cs diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs index 434e9bdf0..50ed57552 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs @@ -1,21 +1,20 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; public class CommandValidation : ICommandDispatcher { private readonly ICommandDispatcher _inner; - private readonly IEnumerable> _validators; + private readonly IServiceProvider _serviceProvider; - public CommandValidation(ICommandDispatcher inner, IEnumerable> validators) + public CommandValidation(ICommandDispatcher inner, IServiceProvider serviceProvider) { _inner = inner; - _validators = validators; + _serviceProvider = serviceProvider; } public async Task SendAsync(ICommand command, CancellationToken ct = default) { - await ValidationHelper.ValidateAsync(command, _validators, ct); + await ValidationHelper.ValidateAsync(command, _serviceProvider, ct); return await _inner.SendAsync(command, ct); } } diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs index 66f9192d3..814f3b143 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs @@ -1,21 +1,20 @@ -using FluentValidation; -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; internal class QueryValidation : IQueryDispatcher { private readonly IQueryDispatcher _inner; - private readonly IEnumerable> _validators; + private readonly IServiceProvider _serviceProvider; - public QueryValidation(IQueryDispatcher inner, IEnumerable> validators) + public QueryValidation(IQueryDispatcher inner, IServiceProvider serviceProvider) { _inner = inner; - _validators = validators; + _serviceProvider = serviceProvider; } public async Task SendAsync(IQuery query, CancellationToken ct = default) { - await ValidationHelper.ValidateAsync(query, _validators, ct); + await ValidationHelper.ValidateAsync(query, _serviceProvider, ct); return await _inner.SendAsync(query, ct); } } diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs b/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs index 496cf9d11..49a9c0a58 100644 --- a/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs +++ b/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs @@ -1,26 +1,24 @@ using FluentValidation; +using Microsoft.Extensions.DependencyInjection; namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; internal static class ValidationHelper { - public static async Task ValidateAsync(object request, IEnumerable validators, CancellationToken ct = default) + public static async Task ValidateAsync(T request, IServiceProvider provider, CancellationToken ct = default) { var requestType = request.GetType(); - var applicableValidators = validators - .Where(v => v.GetType().GetInterfaces() - .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>) && - i.GetGenericArguments()[0].IsAssignableFrom(requestType))) - .ToList(); + var validatorType = typeof(IValidator<>).MakeGenericType(requestType); + var validators = provider.GetServices(validatorType).Cast().ToList(); - if (applicableValidators.Count == 0) return; + if (validators.Count == 0) return; var contextType = typeof(ValidationContext<>).MakeGenericType(requestType); var context = Activator.CreateInstance(contextType, request)!; var failures = new List(); - foreach (var validator in applicableValidators) + foreach (var validator in validators) { var validateAsyncMethod = validator.GetType() .GetMethod("ValidateAsync", new[] { contextType, typeof(CancellationToken) })!; diff --git a/src/framework/Infrastructure/OpenApi/Extensions.cs b/src/framework/Infrastructure/OpenApi/Extensions.cs index ee11438f9..b25553001 100644 --- a/src/framework/Infrastructure/OpenApi/Extensions.cs +++ b/src/framework/Infrastructure/OpenApi/Extensions.cs @@ -39,7 +39,7 @@ public static IServiceCollection ConfigureOpenApi(this IServiceCollection servic .AddApiVersioning(options => { options.ReportApiVersions = true; - options.DefaultApiVersion = new ApiVersion(1); + options.DefaultApiVersion = new ApiVersion(1, 0); options.AssumeDefaultVersionWhenUnspecified = true; options.ApiVersionReader = new UrlSegmentApiVersionReader(); }) diff --git a/src/framework/Modules/Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/AuditingModule.cs index 170db0252..c62c107fb 100644 --- a/src/framework/Modules/Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/AuditingModule.cs @@ -1,24 +1,28 @@ using Asp.Versioning; +using FSH.Framework.Auditing.Data; +using FSH.Framework.Auditing.Features.v1.GetUserTrails; +using FSH.Framework.Auditing.Services; using FSH.Framework.Infrastructure.Messaging.CQRS; -using FSH.Framework.Infrastructure.Modules; +using FSH.Framework.Infrastructure.Persistence; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace FSH.Framework.Auditing.Endpoints; -public class AuditingModule : IFrameworkModule +public static class AuditingModule { - public IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config) + public static IServiceCollection ConfigureAuditingModule(this IServiceCollection services) { + ArgumentNullException.ThrowIfNull(services); services.RegisterCommandAndQueryHandlers(typeof(AuditingModule).Assembly); - - // other registrations + services.AddScoped(); + services.BindDbContext(); + services.AddScoped(provider => provider.GetRequiredService()); return services; } - public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) + public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuilder endpoints) { var apiVersionSet = endpoints.NewApiVersionSet() .HasApiVersion(new ApiVersion(1)) @@ -31,7 +35,7 @@ public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints) .WithOpenApi() .WithApiVersionSet(apiVersionSet); - //GetUserTrailsEndpoint.Map(group); + GetUserTrailsEndpoint.Map(group); return endpoints; } diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs index 378291a69..d24ffb998 100644 --- a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs +++ b/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs @@ -3,6 +3,7 @@ using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Auditing.Features.v1.GetUserTrails; @@ -12,7 +13,7 @@ public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { return endpoints.MapGet("/users/{userId:guid}/trails", async ( Guid userId, - IQueryDispatcher dispatcher, + [FromServices] IQueryDispatcher dispatcher, CancellationToken cancellationToken) => { var query = new GetUserTrailsQuery(userId); diff --git a/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs b/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs index 82621b65e..168446f3e 100644 --- a/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs +++ b/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs @@ -1,5 +1,7 @@ using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; -public record TokenGenerationCommand(string Email, string Password) +public record TokenGenerationCommand( + string Email, + string Password) : ICommand; diff --git a/src/framework/Modules/Identity/IdentityModule.cs b/src/framework/Modules/Identity/IdentityModule.cs index 193a938e3..9da4064f9 100644 --- a/src/framework/Modules/Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/IdentityModule.cs @@ -1,4 +1,5 @@ using Asp.Versioning; +using FluentValidation; using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Core.Persistence; using FSH.Framework.Identity.Authorization; @@ -11,6 +12,7 @@ using FSH.Framework.Identity.Infrastructure.Tokens; using FSH.Framework.Identity.Infrastructure.Users; using FSH.Framework.Identity.v1.Tokens.TokenGeneration; +using FSH.Framework.Identity.v1.Users; using FSH.Framework.Infrastructure.Auth; using FSH.Framework.Infrastructure.Auth.Jwt; using FSH.Framework.Infrastructure.Identity.Roles; @@ -31,7 +33,23 @@ public static class IdentityModule public static IServiceCollection ConfigureIdentityModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); - services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); + + var assemblies = new Assembly[] + { + typeof(IdentityModule).Assembly + }; + services.RegisterCommandAndQueryHandlers(assemblies); + var scanResults = AssemblyScanner + .FindValidatorsInAssemblies(assemblies, true) + .Where(r => r.ValidatorType != typeof(UserImageValidator)) + .ToList(); + + foreach (var result in scanResults) + { + services.AddScoped(result.InterfaceType, result.ValidatorType); + } + + services.AddScoped(); services.AddSingleton(); services.AddScoped(); diff --git a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs index 1e85881e0..887503de1 100644 --- a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs +++ b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs @@ -2,7 +2,7 @@ using FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; -internal class TokenGenerationCommandValidator : AbstractValidator +public class TokenGenerationCommandValidator : AbstractValidator { public TokenGenerationCommandValidator() { diff --git a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs index 824a67912..6202fe896 100644 --- a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs +++ b/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using System.ComponentModel; namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; public static class TokenGenerationEndpoint @@ -12,7 +13,7 @@ internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/tokens", async ( [FromBody] TokenGenerationCommand command, - string tenant, + [DefaultValue("root")] string tenant, [FromServices] ICommandDispatcher dispatcher, HttpContext context, CancellationToken cancellationToken) => diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs index a72a8e16d..39e3651bf 100644 --- a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs @@ -3,6 +3,7 @@ using FSH.Framework.Tenant.Contracts.v1.ActivateTenant; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace FSH.Framework.Tenant.Features.v1.ActivateTenant; @@ -10,11 +11,11 @@ public static class ActivateTenantEndpoint { public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/{id}/activate", async (ICommandDispatcher dispatcher, string id) + return endpoints.MapPost("/{id}/activate", async ([FromServices] ICommandDispatcher dispatcher, string id) => await dispatcher.SendAsync(new ActivateTenantCommand(id))) .WithName(nameof(ActivateTenantEndpoint)) - .WithSummary("activate tenant") + .WithSummary("Activate Tenant") .RequirePermission("Permissions.Tenants.Update") - .WithDescription("activate tenant"); + .WithDescription("Activate Tenant"); } } diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index bc440df3d..07129f53b 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -1,3 +1,4 @@ +using FSH.Framework.Auditing.Endpoints; using FSH.Framework.Identity; using FSH.Framework.Infrastructure; using FSH.Framework.Tenant; @@ -8,18 +9,21 @@ builder.ConfigureFshFramework(); builder.Services.ConfigureTenantModule(); builder.Services.ConfigureIdentityModule(); +builder.Services.ConfigureAuditingModule(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.MapOpenApi(); - app.MapScalarApiReference(); + string[] versions = ["v1", "v2"]; + app.MapScalarApiReference(options => options.AddDocuments(versions)); } app.UseFshMultiTenancy(); app.UseFshFramework(); app.MapIdentityEndpoints(); +app.MapAuditingEndpoints(); app.UseHttpsRedirection(); await app.RunAsync(); \ No newline at end of file diff --git a/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.Designer.cs b/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.Designer.cs new file mode 100644 index 000000000..9e61795ca --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.Designer.cs @@ -0,0 +1,80 @@ +// +using System; +using FSH.Framework.Auditing.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Auditing +{ + [DbContext(typeof(AuditingDbContext))] + [Migration("20250417072044_Add Auditing Schema")] + partial class AddAuditingSchema + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FSH.Framework.Auditing.Core.Entities.Trail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityName") + .HasColumnType("text"); + + b.Property("KeyValuesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ModifiedPropertiesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("NewValuesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("OldValuesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("Operation") + .HasColumnType("integer"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Trails", "auditing"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs b/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs new file mode 100644 index 000000000..a950fb1a5 --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Auditing; + +/// +public partial class AddAuditingSchema : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "auditing"); + + migrationBuilder.CreateTable( + name: "Trails", + schema: "auditing", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + DateTime = table.Column(type: "timestamp with time zone", nullable: false), + Operation = table.Column(type: "integer", nullable: false), + Description = table.Column(type: "text", nullable: false), + EntityName = table.Column(type: "text", nullable: true), + KeyValuesJson = table.Column(type: "text", nullable: false), + OldValuesJson = table.Column(type: "text", nullable: false), + NewValuesJson = table.Column(type: "text", nullable: false), + ModifiedPropertiesJson = table.Column(type: "text", nullable: false), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Trails", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Trails", + schema: "auditing"); + } +} diff --git a/src/framework/playground/migrations/PostgreSQL/Auditing/AuditingDbContextModelSnapshot.cs b/src/framework/playground/migrations/PostgreSQL/Auditing/AuditingDbContextModelSnapshot.cs new file mode 100644 index 000000000..02107a941 --- /dev/null +++ b/src/framework/playground/migrations/PostgreSQL/Auditing/AuditingDbContextModelSnapshot.cs @@ -0,0 +1,77 @@ +// +using System; +using FSH.Framework.Auditing.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FSH.PlayGround.Migrations.PostgreSQL.Auditing +{ + [DbContext(typeof(AuditingDbContext))] + partial class AuditingDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FSH.Framework.Auditing.Core.Entities.Trail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityName") + .HasColumnType("text"); + + b.Property("KeyValuesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ModifiedPropertiesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("NewValuesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("OldValuesJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("Operation") + .HasColumnType("integer"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Trails", "auditing"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); +#pragma warning restore 612, 618 + } + } +} From 6b00edc3f02cb2dc8c67542dd312104536c06e64 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 17 Apr 2025 17:55:20 +0530 Subject: [PATCH 37/54] health check --- src/framework/Infrastructure/Extensions.cs | 2 + .../BearerSecuritySchemeTransformer.cs | 43 +++++++++++++++++++ .../CreateTenantCommandHandler.cs | 2 +- .../v1/CreateTenant/CreateTenantEndpoint.cs | 2 +- src/framework/Modules/Tenant/TenantModule.cs | 8 ++++ .../playground/PlayGround.Api/Program.cs | 6 ++- 6 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/framework/Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs index 5a8ec9c1e..abe8177f2 100644 --- a/src/framework/Infrastructure/Extensions.cs +++ b/src/framework/Infrastructure/Extensions.cs @@ -72,6 +72,8 @@ public static WebApplication UseFshFramework(this WebApplication app) app.UseRouting(); app.UseStaticFiles(); + app.MapHealthChecks("/health").AllowAnonymous(); + var assetsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"); if (!Directory.Exists(assetsPath)) { diff --git a/src/framework/Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs b/src/framework/Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs new file mode 100644 index 000000000..1839b730e --- /dev/null +++ b/src/framework/Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.OpenApi; +using Microsoft.OpenApi.Models; + +namespace FSH.Framework.Infrastructure.OpenApi; +public sealed class BearerSecuritySchemeTransformer : IOpenApiDocumentTransformer +{ + private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider; + + public BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) + { + _authenticationSchemeProvider = authenticationSchemeProvider; + } + + public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken) + { + var authenticationSchemes = await _authenticationSchemeProvider.GetAllSchemesAsync(); + if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer")) + { + var requirements = new Dictionary + { + ["Bearer"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.Http, + Scheme = "bearer", + In = ParameterLocation.Header, + BearerFormat = "JWT" + } + }; + + document.Components ??= new OpenApiComponents(); + document.Components.SecuritySchemes = requirements; + + foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations)) + { + operation.Value.Security.Add(new OpenApiSecurityRequirement + { + [new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] = Array.Empty() + }); + } + } + } +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs index 1b5dc1717..1a2f7dcca 100644 --- a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs @@ -3,7 +3,7 @@ using FSH.Framework.Tenant.Services; namespace FSH.Framework.Tenant.Features.v1.CreateTenant; -internal class CreateTenantCommandHandler(ITenantService service) +public class CreateTenantCommandHandler(ITenantService service) : ICommandHandler { public async Task HandleAsync( diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs index 265c47f4e..c249c036b 100644 --- a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs @@ -9,7 +9,7 @@ namespace FSH.Framework.Tenant.Features.v1.CreateTenant; public static class CreateTenantEndpoint { - internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) + public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/", async ( [FromBody] CreateTenantCommand command, diff --git a/src/framework/Modules/Tenant/TenantModule.cs b/src/framework/Modules/Tenant/TenantModule.cs index 4d0d131e6..2aecaf9ea 100644 --- a/src/framework/Modules/Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/TenantModule.cs @@ -2,6 +2,7 @@ using Finbuckle.MultiTenant; using Finbuckle.MultiTenant.Abstractions; using Finbuckle.MultiTenant.Stores.DistributedCacheStore; +using FluentValidation; using FSH.Framework.Core.Persistence; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Persistence; @@ -26,6 +27,13 @@ public static IServiceCollection ConfigureTenantModule(this IServiceCollection s { ArgumentNullException.ThrowIfNull(services); services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); + + var assemblies = new Assembly[] + { + typeof(TenantModule).Assembly + }; + services.AddValidatorsFromAssemblies(assemblies, includeInternalTypes: true); + services.AddTransient(); services.BindDbContext(); services diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index 07129f53b..6765e77a2 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -1,11 +1,15 @@ using FSH.Framework.Auditing.Endpoints; using FSH.Framework.Identity; using FSH.Framework.Infrastructure; +using FSH.Framework.Infrastructure.OpenApi; using FSH.Framework.Tenant; using Scalar.AspNetCore; var builder = WebApplication.CreateBuilder(args); -builder.Services.AddOpenApi(); +builder.Services.AddOpenApi("v1", options => +{ + options.AddDocumentTransformer(); +}); builder.ConfigureFshFramework(); builder.Services.ConfigureTenantModule(); builder.Services.ConfigureIdentityModule(); From c9d6debe9cb9b9beda0240d66f8fe7c502d5c920 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 17 Apr 2025 17:56:58 +0530 Subject: [PATCH 38/54] code cleanup --- src/framework/Core/Domain/BaseEntity.cs | 6 +++--- src/framework/Core/Domain/Contracts/IEntity.cs | 4 ++-- .../Infrastructure/Caching/DistributedCacheService.cs | 4 ++-- .../Infrastructure/HealthChecks/HealthCheckEndpoint.cs | 10 +++++----- .../HealthChecks/HealthCheckMiddleware.cs | 4 ++-- .../Jobs/HangfireCustomBasicAuthenticationFilter.cs | 2 +- src/framework/Infrastructure/Jobs/HangfireService.cs | 2 +- .../Infrastructure/Logging/Serilog/Extensions.cs | 4 ++-- .../Infrastructure/Messaging/Events/Extensions.cs | 4 ++-- .../Infrastructure/OpenApi/ConfigureSwaggerOptions.cs | 4 ++-- .../Infrastructure/OpenApi/SwaggerDefaultValues.cs | 4 ++-- .../Persistence/AppendGlobalQueryFilterExtension.cs | 2 +- src/framework/Infrastructure/RateLimit/Extensions.cs | 8 ++++---- .../Shared/Extensions/ClaimsPrincipalExtensions.cs | 4 ++-- 14 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/framework/Core/Domain/BaseEntity.cs b/src/framework/Core/Domain/BaseEntity.cs index acc8ad24e..953fbd2e5 100644 --- a/src/framework/Core/Domain/BaseEntity.cs +++ b/src/framework/Core/Domain/BaseEntity.cs @@ -1,7 +1,7 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations.Schema; -using FSH.Framework.Core.Domain.Contracts; +using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.Messaging.Events; +using System.Collections.ObjectModel; +using System.ComponentModel.DataAnnotations.Schema; namespace FSH.Framework.Core.Domain; diff --git a/src/framework/Core/Domain/Contracts/IEntity.cs b/src/framework/Core/Domain/Contracts/IEntity.cs index 67c24d978..497568f6c 100644 --- a/src/framework/Core/Domain/Contracts/IEntity.cs +++ b/src/framework/Core/Domain/Contracts/IEntity.cs @@ -1,5 +1,5 @@ -using System.Collections.ObjectModel; -using FSH.Framework.Core.Messaging.Events; +using FSH.Framework.Core.Messaging.Events; +using System.Collections.ObjectModel; namespace FSH.Framework.Core.Domain.Contracts; diff --git a/src/framework/Infrastructure/Caching/DistributedCacheService.cs b/src/framework/Infrastructure/Caching/DistributedCacheService.cs index 3b8aa6df2..4a42e71ae 100644 --- a/src/framework/Infrastructure/Caching/DistributedCacheService.cs +++ b/src/framework/Infrastructure/Caching/DistributedCacheService.cs @@ -1,8 +1,8 @@ -using System.Text; -using System.Text.Json; using FSH.Framework.Core.Caching; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; +using System.Text; +using System.Text.Json; namespace FSH.Framework.Infrastructure.Caching; diff --git a/src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs b/src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs index 785aac77b..af26e38d5 100644 --- a/src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs +++ b/src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs @@ -1,9 +1,9 @@ -using System.Text.Json; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; +using System.Text.Json; namespace FSH.Framework.Infrastructure.HealthChecks; public static class HealthCheckEndpoint @@ -14,7 +14,7 @@ internal static RouteHandlerBuilder MapCustomHealthCheckEndpoint(this IEndpointR { var healthCheckService = context.RequestServices.GetRequiredService(); var report = healthCheckService.CheckHealthAsync().Result; - + var response = new { status = report.Status.ToString(), @@ -24,10 +24,10 @@ internal static RouteHandlerBuilder MapCustomHealthCheckEndpoint(this IEndpointR status = entry.Value.Status.ToString(), description = entry.Value.Description }), - + duration = report.TotalDuration }; - + context.Response.ContentType = "application/json"; return JsonSerializer.Serialize(response); }) diff --git a/src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs b/src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs index 031156870..7f7666973 100644 --- a/src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs +++ b/src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs @@ -1,6 +1,6 @@ -using System.Text.Json; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Diagnostics.HealthChecks; +using System.Text.Json; namespace FSH.Framework.Infrastructure.HealthChecks; diff --git a/src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs b/src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs index 2cc8980d4..731b1b82f 100644 --- a/src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs +++ b/src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs @@ -1,9 +1,9 @@ -using System.Net.Http.Headers; using Hangfire.Dashboard; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Primitives; +using System.Net.Http.Headers; namespace FSH.Framework.Infrastructure.Jobs; diff --git a/src/framework/Infrastructure/Jobs/HangfireService.cs b/src/framework/Infrastructure/Jobs/HangfireService.cs index 1c4785cd1..027aea85b 100644 --- a/src/framework/Infrastructure/Jobs/HangfireService.cs +++ b/src/framework/Infrastructure/Jobs/HangfireService.cs @@ -1,6 +1,6 @@ -using System.Linq.Expressions; using FSH.Framework.Core.Jobs; using Hangfire; +using System.Linq.Expressions; namespace FSH.Framework.Infrastructure.Jobs; diff --git a/src/framework/Infrastructure/Logging/Serilog/Extensions.cs b/src/framework/Infrastructure/Logging/Serilog/Extensions.cs index 25a8dba17..d02fee79c 100644 --- a/src/framework/Infrastructure/Logging/Serilog/Extensions.cs +++ b/src/framework/Infrastructure/Logging/Serilog/Extensions.cs @@ -22,7 +22,7 @@ public static WebApplicationBuilder ConfigureSerilog(this WebApplicationBuilder { var (key, value) = header.Split('=') switch { - [string k, string v] => (k, v), + [string k, string v] => (k, v), var v => throw new Exception($"Invalid header format {v}") }; @@ -32,7 +32,7 @@ public static WebApplicationBuilder ConfigureSerilog(this WebApplicationBuilder //To remove the duplicate issue, we can use the below code to get the key and value from the configuration var (otelResourceAttribute, otelResourceAttributeValue) = builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]?.Split('=') switch { - [string k, string v] => (k, v), + [string k, string v] => (k, v), _ => throw new Exception($"Invalid header format {builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]}") }; options.ResourceAttributes.Add(otelResourceAttribute, otelResourceAttributeValue); diff --git a/src/framework/Infrastructure/Messaging/Events/Extensions.cs b/src/framework/Infrastructure/Messaging/Events/Extensions.cs index 9f2584951..d35996dbd 100644 --- a/src/framework/Infrastructure/Messaging/Events/Extensions.cs +++ b/src/framework/Infrastructure/Messaging/Events/Extensions.cs @@ -1,6 +1,6 @@ -using System.Reflection; -using FSH.Framework.Core.Messaging.Events; +using FSH.Framework.Core.Messaging.Events; using Microsoft.Extensions.DependencyInjection; +using System.Reflection; namespace FSH.Framework.Infrastructure.Messaging.Events; public static class Extensions diff --git a/src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs b/src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs index 71eed3eb7..34fda3eeb 100644 --- a/src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs +++ b/src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs @@ -1,9 +1,9 @@ -using System.Text; -using Asp.Versioning.ApiExplorer; +using Asp.Versioning.ApiExplorer; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; +using System.Text; namespace FSH.Framework.Infrastructure.OpenApi; public class ConfigureSwaggerOptions : IConfigureOptions diff --git a/src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs b/src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs index b872e6902..73c863c36 100644 --- a/src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs +++ b/src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs @@ -1,8 +1,8 @@ -using System.Text.Json; -using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; +using System.Text.Json; namespace FSH.Framework.Infrastructure.OpenApi; public class SwaggerDefaultValues : IOperationFilter diff --git a/src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs b/src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs index dbd09831d..2186473b7 100644 --- a/src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs +++ b/src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs @@ -1,6 +1,6 @@ -using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; +using System.Linq.Expressions; namespace FSH.Framework.Infrastructure.Persistence; diff --git a/src/framework/Infrastructure/RateLimit/Extensions.cs b/src/framework/Infrastructure/RateLimit/Extensions.cs index 3b00e7d85..b0960d29f 100644 --- a/src/framework/Infrastructure/RateLimit/Extensions.cs +++ b/src/framework/Infrastructure/RateLimit/Extensions.cs @@ -1,10 +1,10 @@ -using System.Threading.RateLimiting; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.RateLimiting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using System.Threading.RateLimiting; namespace FSH.Framework.Infrastructure.RateLimit; @@ -41,11 +41,11 @@ internal static IServiceCollection ConfigureRateLimit(this IServiceCollection se return services; } - + internal static IApplicationBuilder UseRateLimit(this IApplicationBuilder app) { var options = app.ApplicationServices.GetRequiredService>().Value; - + if (options.EnableRateLimiting) { app.UseRateLimiter(); diff --git a/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs b/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs index 0d351dfcd..7baf98a8d 100644 --- a/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs +++ b/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs @@ -1,5 +1,5 @@ -using System.Security.Claims; -using FSH.Framework.Shared.Authorization; +using FSH.Framework.Shared.Authorization; +using System.Security.Claims; namespace FSH.Framework.Shared.Extensions; From 9f4ddd2226cd7f03555bba2a21027934e02e774e Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 17 Apr 2025 18:43:47 +0530 Subject: [PATCH 39/54] fix audit event handler --- src/framework/Infrastructure/Extensions.cs | 2 +- .../Events/InMemoryEventPublisher.cs | 13 +++++++++++-- .../Modules/Auditing/AuditingModule.cs | 2 ++ .../Auditing/Data/AuditingDbContext.cs | 16 +++++++++++++--- .../Auditing/Data/AuditingDbInitializer.cs | 19 +++++++++++++++++++ .../playground/PlayGround.Api/Program.cs | 10 ++++++++++ 6 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/framework/Modules/Auditing/Data/AuditingDbInitializer.cs diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Infrastructure/Extensions.cs index abe8177f2..515529b0b 100644 --- a/src/framework/Infrastructure/Extensions.cs +++ b/src/framework/Infrastructure/Extensions.cs @@ -53,7 +53,7 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui // register messaging services builder.Services.RegisterCommandAndQueryDispatchers(); - builder.Services.RegisterInMemoryEventBus(); + builder.Services.RegisterInMemoryEventBus(assemblies); builder.Services.ConfigureRateLimit(builder.Configuration); builder.Services.ConfigureSecurityHeaders(builder.Configuration); diff --git a/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs b/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs index c8ec9f657..5cdb4cdaa 100644 --- a/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs +++ b/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs @@ -15,7 +15,10 @@ public async Task PublishAsync(IEvent appEvent, CancellationToken cancellationTo ArgumentNullException.ThrowIfNull(appEvent); using var scope = _serviceProvider.CreateScope(); - var handlers = scope.ServiceProvider.GetServices>(); + + // Get handler type dynamically based on the event's runtime type + var handlerType = typeof(IEventHandler<>).MakeGenericType(appEvent.GetType()); + var handlers = scope.ServiceProvider.GetServices(handlerType); foreach (var handler in handlers) { @@ -27,7 +30,13 @@ public async Task PublishAsync(IEvent appEvent, CancellationToken cancellationTo try { attempt++; - await handler.HandleAsync(appEvent, cancellationToken); + var method = handlerType.GetMethod("HandleAsync"); + + if (method is not null) + { + await (Task)method.Invoke(handler, new object[] { appEvent, cancellationToken })!; + } + break; // Success } catch (Exception ex) diff --git a/src/framework/Modules/Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/AuditingModule.cs index c62c107fb..8a318cf19 100644 --- a/src/framework/Modules/Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/AuditingModule.cs @@ -2,6 +2,7 @@ using FSH.Framework.Auditing.Data; using FSH.Framework.Auditing.Features.v1.GetUserTrails; using FSH.Framework.Auditing.Services; +using FSH.Framework.Core.Persistence; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Persistence; using Microsoft.AspNetCore.Builder; @@ -15,6 +16,7 @@ public static class AuditingModule public static IServiceCollection ConfigureAuditingModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); + services.AddScoped(); services.RegisterCommandAndQueryHandlers(typeof(AuditingModule).Assembly); services.AddScoped(); services.BindDbContext(); diff --git a/src/framework/Modules/Auditing/Data/AuditingDbContext.cs b/src/framework/Modules/Auditing/Data/AuditingDbContext.cs index 736ee1701..447d9fd50 100644 --- a/src/framework/Modules/Auditing/Data/AuditingDbContext.cs +++ b/src/framework/Modules/Auditing/Data/AuditingDbContext.cs @@ -1,12 +1,22 @@ -using FSH.Framework.Auditing.Core.Entities; +using Finbuckle.MultiTenant.Abstractions; +using FSH.Framework.Auditing.Core.Entities; +using FSH.Framework.Core.Messaging.Events; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Infrastructure.Persistence; +using FSH.Framework.Shared.Multitenancy; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; namespace FSH.Framework.Auditing.Data; -public class AuditingDbContext : DbContext, IAuditingDbContext +public class AuditingDbContext : FshDbContext, IAuditingDbContext { public DbSet Trails { get; set; } - public AuditingDbContext(DbContextOptions options) : base(options) { } + public AuditingDbContext( + IMultiTenantContextAccessor multiTenantContextAccessor, + DbContextOptions options, + IEventPublisher publisher, + IOptions settings) : base(multiTenantContextAccessor, options, publisher, settings) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/src/framework/Modules/Auditing/Data/AuditingDbInitializer.cs b/src/framework/Modules/Auditing/Data/AuditingDbInitializer.cs new file mode 100644 index 000000000..66d0ebe23 --- /dev/null +++ b/src/framework/Modules/Auditing/Data/AuditingDbInitializer.cs @@ -0,0 +1,19 @@ +using FSH.Framework.Core.Persistence; +using Microsoft.EntityFrameworkCore; + +namespace FSH.Framework.Auditing.Data; +public class AuditingDbInitializer(AuditingDbContext context) : IDbInitializer +{ + public async Task MigrateAsync(CancellationToken cancellationToken) + { + if ((await context.Database.GetPendingMigrationsAsync(cancellationToken).ConfigureAwait(false)).Any()) + { + await context.Database.MigrateAsync(cancellationToken).ConfigureAwait(false); + } + } + + public Task SeedAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index 6765e77a2..07545c9a5 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -1,9 +1,11 @@ using FSH.Framework.Auditing.Endpoints; using FSH.Framework.Identity; using FSH.Framework.Infrastructure; +using FSH.Framework.Infrastructure.Messaging.Events; using FSH.Framework.Infrastructure.OpenApi; using FSH.Framework.Tenant; using Scalar.AspNetCore; +using System.Reflection; var builder = WebApplication.CreateBuilder(args); builder.Services.AddOpenApi("v1", options => @@ -15,6 +17,14 @@ builder.Services.ConfigureIdentityModule(); builder.Services.ConfigureAuditingModule(); +var assemblies = new Assembly[] + { + typeof(TenantModule).Assembly, + typeof(IdentityModule).Assembly, + typeof(AuditingModule).Assembly + }; +builder.Services.RegisterInMemoryEventBus(assemblies); + var app = builder.Build(); if (app.Environment.IsDevelopment()) { From ac0c13fa6c632d4da471e670982d2918636d7dac Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 17 Apr 2025 20:39:27 +0530 Subject: [PATCH 40/54] cleanup --- src/framework/FSH.Framework.sln | 9 +++++++-- .../{ => Features}/v1/RoleClaims/FshRoleClaim.cs | 0 .../v1/Roles/DeleteRole/DeleteRoleEndpoint.cs | 0 .../Modules/Identity/{ => Features}/v1/Roles/FshRole.cs | 1 + .../{ => Features}/v1/Roles/GetRole/GetRoleEndpoint.cs | 0 .../GetRoleWithPermissions/GetRolePermissionsEndpoint.cs | 0 .../{ => Features}/v1/Roles/GetRoles/GetRolesEndpoint.cs | 0 .../Identity/{ => Features}/v1/Roles/RoleService.cs | 0 .../UpdatePermissionsCommandValidator.cs | 0 .../UpdateRolePermissionsEndpoint.cs | 0 .../v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs | 0 .../v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs | 0 .../v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs | 0 .../Tokens/RefreshToken/RefreshTokenCommandValidator.cs | 0 .../v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs | 0 .../TokenGeneration/TokenGenerationCommandHandler.cs | 0 .../TokenGeneration/TokenGenerationCommandValidator.cs | 0 .../v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs | 0 .../AssignUserRoles/AssignUserRolesCommandHandler.cs | 0 .../v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs | 0 .../v1/Users/ChangePassword/ChangePasswordEndpoint.cs | 0 .../v1/Users/ChangePassword/ChangePasswordValidator.cs | 0 .../v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs | 0 .../v1/Users/DeleteUser/DeleteUserEndpoint.cs | 0 .../ForgotPassword/ForgotPasswordCommandValidator.cs | 0 .../v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs | 0 .../Modules/Identity/{ => Features}/v1/Users/FshUser.cs | 0 .../{ => Features}/v1/Users/GetUser/GetUserEndpoint.cs | 0 .../GetUserPermissions/GetUserPermissionsEndpoint.cs | 0 .../v1/Users/GetUserProfile/GetUserProfileEndpoint.cs | 0 .../v1/Users/GetUserRoles/GetUserRolesEndpoint.cs | 0 .../v1/Users/GetUsers/GetUsersListEndpoint.cs | 0 .../v1/Users/RegisterUser/RegisterUserEndpoint.cs | 0 .../Users/ResetPassword/ResetPasswordCommandValidator.cs | 0 .../v1/Users/ResetPassword/ResetPasswordEndpoint.cs | 0 .../Users/SelfRegistration/SelfRegisterUserEndpoint.cs | 0 .../Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs | 0 .../v1/Users/UpdateUser/UpdateUserCommandValidator.cs | 0 .../v1/Users/UpdateUser/UpdateUserEndpoint.cs | 0 .../{ => Features}/v1/Users/UserImageValidator.cs | 0 .../{PostgreSQL.csproj => Migrations.PostgreSQL.csproj} | 0 41 files changed, 8 insertions(+), 2 deletions(-) rename src/framework/Modules/Identity/{ => Features}/v1/RoleClaims/FshRoleClaim.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/FshRole.cs (99%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/GetRole/GetRoleEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/GetRoles/GetRolesEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/RoleService.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ChangePassword/ChangePasswordEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ChangePassword/ChangePasswordValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/DeleteUser/DeleteUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/FshUser.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/GetUser/GetUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/GetUsers/GetUsersListEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/RegisterUser/RegisterUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ResetPassword/ResetPasswordEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/UpdateUser/UpdateUserCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/UpdateUser/UpdateUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Features}/v1/Users/UserImageValidator.cs (100%) rename src/framework/playground/migrations/PostgreSQL/{PostgreSQL.csproj => Migrations.PostgreSQL.csproj} (100%) diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index 5ba167f49..ef8507d6d 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -32,10 +32,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PlayGround", "PlayGround", "{C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostgreSQL", "playground\migrations\PostgreSQL\PostgreSQL.csproj", "{EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrations.PostgreSQL", "playground\migrations\PostgreSQL\Migrations.PostgreSQL.csproj", "{EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayGround.Api", "playground\PlayGround.Api\PlayGround.Api.csproj", "{2527B9BA-2168-ED23-7E12-CF3C7C901279}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{83139AD6-D37E-4209-84A2-5E9023CEDA78}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -91,6 +93,9 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45} = {83139AD6-D37E-4209-84A2-5E9023CEDA78} + {60DF219E-E1EB-428E-BB1F-F0342D42699F} = {83139AD6-D37E-4209-84A2-5E9023CEDA78} + {09380C15-F138-4305-A595-F4C7E16B6E78} = {83139AD6-D37E-4209-84A2-5E9023CEDA78} {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {E39A5A4F-D453-A6A2-CA94-468FD795246C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} @@ -101,7 +106,7 @@ Global {2527B9BA-2168-ED23-7E12-CF3C7C901279} = {C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {438A0F87-0F3E-43C4-A352-264E0C21F77B} SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} + SolutionGuid = {438A0F87-0F3E-43C4-A352-264E0C21F77B} EndGlobalSection EndGlobal diff --git a/src/framework/Modules/Identity/v1/RoleClaims/FshRoleClaim.cs b/src/framework/Modules/Identity/Features/v1/RoleClaims/FshRoleClaim.cs similarity index 100% rename from src/framework/Modules/Identity/v1/RoleClaims/FshRoleClaim.cs rename to src/framework/Modules/Identity/Features/v1/RoleClaims/FshRoleClaim.cs diff --git a/src/framework/Modules/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Roles/FshRole.cs b/src/framework/Modules/Identity/Features/v1/Roles/FshRole.cs similarity index 99% rename from src/framework/Modules/Identity/v1/Roles/FshRole.cs rename to src/framework/Modules/Identity/Features/v1/Roles/FshRole.cs index cb7501d0e..bc52e556c 100644 --- a/src/framework/Modules/Identity/v1/Roles/FshRole.cs +++ b/src/framework/Modules/Identity/Features/v1/Roles/FshRole.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Identity; + namespace FSH.Framework.Identity.Infrastructure.Roles; public class FshRole : IdentityRole { diff --git a/src/framework/Modules/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/GetRole/GetRoleEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/GetRoles/GetRolesEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Roles/RoleService.cs b/src/framework/Modules/Identity/Features/v1/Roles/RoleService.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/RoleService.cs rename to src/framework/Modules/Identity/Features/v1/Roles/RoleService.cs diff --git a/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs b/src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs rename to src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs diff --git a/src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs b/src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs rename to src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs diff --git a/src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs b/src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs rename to src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs diff --git a/src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs b/src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs rename to src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs diff --git a/src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs b/src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs rename to src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs diff --git a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs b/src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs rename to src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs diff --git a/src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs b/src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs rename to src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs diff --git a/src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ChangePassword/ChangePasswordValidator.cs rename to src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs diff --git a/src/framework/Modules/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/DeleteUser/DeleteUserEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs b/src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs rename to src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs diff --git a/src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/FshUser.cs b/src/framework/Modules/Identity/Features/v1/Users/FshUser.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/FshUser.cs rename to src/framework/Modules/Identity/Features/v1/Users/FshUser.cs diff --git a/src/framework/Modules/Identity/v1/Users/GetUser/GetUserEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/GetUser/GetUserEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/GetUsers/GetUsersListEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/RegisterUser/RegisterUserEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs b/src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs rename to src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs diff --git a/src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ResetPassword/ResetPasswordEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserCommandValidator.cs rename to src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs diff --git a/src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs b/src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/UpdateUser/UpdateUserEndpoint.cs rename to src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs diff --git a/src/framework/Modules/Identity/v1/Users/UserImageValidator.cs b/src/framework/Modules/Identity/Features/v1/Users/UserImageValidator.cs similarity index 100% rename from src/framework/Modules/Identity/v1/Users/UserImageValidator.cs rename to src/framework/Modules/Identity/Features/v1/Users/UserImageValidator.cs diff --git a/src/framework/playground/migrations/PostgreSQL/PostgreSQL.csproj b/src/framework/playground/migrations/PostgreSQL/Migrations.PostgreSQL.csproj similarity index 100% rename from src/framework/playground/migrations/PostgreSQL/PostgreSQL.csproj rename to src/framework/playground/migrations/PostgreSQL/Migrations.PostgreSQL.csproj From 6af15b847dd034cd8d8b7140adf3434d7577de5c Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Fri, 18 Apr 2025 00:13:41 +0530 Subject: [PATCH 41/54] restructure (again!) --- src/framework/Directory.Build.props | 12 ++ src/framework/FSH.Framework.sln | 116 ++++++++++-------- .../Modules/Auditing/Auditing.csproj | 16 --- .../AuditingConstants.cs | 0 .../Dtos/TrailDto.cs | 0 .../Enums/AuditOperation.cs | 0 .../IntegrationEvents/AuditPublishedEvent.cs | 0 .../Modules.Auditing.Contracts.csproj} | 4 +- .../v1/GetUserTrails/GetUserTrailsQuery.cs | 0 .../GetUserTrailsQueryResponse.cs | 0 .../{ => Modules.Auditing}/AuditingModule.cs | 0 .../Data/AuditingConfiguration.cs | 0 .../Data/AuditingDbContext.cs | 0 .../Data/AuditingDbInitializer.cs | 0 .../Data/IAuditingDbContext.cs | 0 .../Data/Interceptors/AuditInterceptor.cs | 0 .../AuditPublishedIntegrationEventHandler.cs | 0 .../Features/Entities/Trail.cs | 0 .../v1/GetUserTrails/GetUserTrailsEndpoint.cs | 0 .../GetUserTrailsQueryHandler.cs | 0 .../GetUserTrailsQueryValidator.cs | 0 .../Mappings/TrailMappings.cs | 0 .../Modules.Auditing/Modules.Auditing.csproj | 20 +++ .../Services/AuditService.cs | 0 .../Services/IAuditService.cs | 0 .../Caching/CacheOptions.cs | 0 .../Caching/CacheServiceExtensions.cs | 0 .../Caching/ICacheService.cs | 0 .../Domain/AuditableEntity.cs | 0 .../Modules.Common.Core}/Domain/BaseEntity.cs | 0 .../Domain/Contracts/IAggregateRoot.cs | 0 .../Domain/Contracts/IAuditable.cs | 0 .../Domain/Contracts/IEntity.cs | 0 .../Domain/Contracts/ISoftDeletable.cs | 0 .../Exceptions/CustomException.cs | 0 .../Exceptions/ForbiddenException.cs | 0 .../Exceptions/NotFoundException.cs | 0 .../Exceptions/UnauthorizedException.cs | 0 .../ExecutionContext/ICurrentUser.cs | 0 .../ICurrentUserInitializer.cs | 0 .../Common/Modules.Common.Core}/FshCore.cs | 0 .../Helpers/JsonHelpers.cs | 0 .../Modules.Common.Core}/Jobs/IJobService.cs | 0 .../Modules.Common.Core}/Mail/IMailService.cs | 0 .../Modules.Common.Core}/Mail/MailOptions.cs | 0 .../Modules.Common.Core}/Mail/MailRequest.cs | 0 .../Messaging/CQRS/ICommand.cs | 0 .../Messaging/CQRS/ICommandDispatcher.cs | 0 .../Messaging/CQRS/ICommandHandler.cs | 0 .../Messaging/CQRS/IQuery.cs | 0 .../Messaging/CQRS/IQueryDispatcher.cs | 0 .../Messaging/CQRS/IQueryHandler.cs | 0 .../Messaging/CQRS/IRequest.cs | 0 .../Messaging/Events/AppEvent.cs | 0 .../Messaging/Events/IEvent.cs | 0 .../Messaging/Events/IEventHandler.cs | 0 .../Messaging/Events/IEventPublisher.cs | 0 .../Messaging/Events/INotification.cs | 0 .../Messaging/Events/Notification.cs | 0 .../Modules.Common.Core.csproj} | 4 +- .../Modules/ICoreModule.cs | 0 .../Origin/OriginOptions.cs | 0 .../Modules.Common.Core}/Paging/BaseFilter.cs | 0 .../Modules.Common.Core}/Paging/Filter.cs | 0 .../Paging/FilterLogic.cs | 0 .../Paging/FilterOperator.cs | 0 .../Paging/IPageRequest.cs | 0 .../Modules.Common.Core}/Paging/IPagedList.cs | 0 .../Modules.Common.Core}/Paging/PagedList.cs | 0 .../Paging/PaginationFilter.cs | 0 .../Paging/PaginationFilterExtensions.cs | 0 .../Modules.Common.Core}/Paging/Search.cs | 0 .../Persistence/DatabaseOptions.cs | 0 .../Persistence/IConnectionStringValidator.cs | 0 .../Persistence/IDbInitializer.cs | 0 .../Persistence/IRepository.cs | 0 .../EntitiesByBaseFilterSpec.cs | 0 .../EntitiesByPaginationFilterSpec.cs | 0 .../SpecificationBuilderExtensions.cs | 0 .../Modules.Common.Core}/Storage/FileType.cs | 0 .../Storage/FileUploadRequest.cs | 0 .../Storage/IStorageService.cs | 0 .../Caching/DistributedCacheService.cs | 0 .../Caching/Extensions.cs | 0 .../Common/Extensions/EnumExtensions.cs | 0 .../Common/Extensions/RegexExtensions.cs | 0 .../Constants/QueryStringKeys.cs | 0 .../Cors/CorsOptions.cs | 0 .../Cors/Extensions.cs | 0 .../Exceptions/CustomExceptionHandler.cs | 0 .../Extensions.cs | 0 .../Extensions/PagedListExtensions.cs | 0 .../Extensions/RepositoryExtensions.cs | 0 .../FshInfrastructure.cs | 0 .../HealthChecks/HealthCheckEndpoint.cs | 0 .../HealthChecks/HealthCheckMiddleware.cs | 0 .../Jobs/Extensions.cs | 0 .../Jobs/FshJobActivator.cs | 0 .../Jobs/FshJobFilter.cs | 0 ...HangfireCustomBasicAuthenticationFilter.cs | 0 .../Jobs/HangfireOptions.cs | 0 .../Jobs/HangfireService.cs | 0 .../Jobs/LogJobFilter.cs | 0 .../Logging/Serilog/Extensions.cs | 0 .../Logging/Serilog/StaticLogger.cs | 0 .../Mail/Extensions.cs | 0 .../Mail/SmtpMailService.cs | 0 .../Messaging/CQRS/CommandDispatcher.cs | 0 .../Messaging/CQRS/Extensions.cs | 0 .../Messaging/CQRS/QueryDispatcher.cs | 0 .../CQRS/Validation/CommandValidation.cs | 0 .../CQRS/Validation/QueryValidation.cs | 0 .../CQRS/Validation/ValidationHelper.cs | 0 .../Messaging/Events/Extensions.cs | 0 .../Events/InMemoryEventPublisher.cs | 0 .../Modules.Common.Infrastructure.csproj} | 8 +- .../Modules/Extensions.cs | 0 .../Modules/IFrameworkModule.cs | 0 .../Modules/IModule.cs | 0 .../BearerSecuritySchemeTransformer.cs | 0 .../OpenApi/ConfigureSwaggerOptions.cs | 0 .../OpenApi/Extensions.cs | 0 .../OpenApi/SwaggerDefaultValues.cs | 0 .../AppendGlobalQueryFilterExtension.cs | 0 .../Persistence/DbProviders.cs | 0 .../Persistence/Extensions.cs | 0 .../Persistence/FshDbContext.cs | 0 .../Services/ConnectionStringValidator.cs | 0 .../RateLimit/Extensions.cs | 0 .../RateLimit/RateLimitOptions.cs | 0 .../SecurityHeaders/Extensions.cs | 0 .../SecurityHeaders/SecurityHeaderOptions.cs | 0 .../SecurityHeaders/SecurityHeaders.cs | 0 .../Storage/LocalStorageService.cs | 0 .../Storage/StorageServiceRegistration.cs | 0 .../Authorization/CustomClaims.cs | 0 .../Authorization/EndpointExtensions.cs | 0 .../RequiredPermissionAttribute.cs | 0 .../Constants/AuthenticationConstants.cs | 0 .../Constants/FshActions.cs | 0 .../Constants/FshClaims.cs | 0 .../Constants/FshPermissions.cs | 0 .../Constants/FshResources.cs | 0 .../Constants/FshRoles.cs | 0 .../Constants/TenantConstants.cs | 0 .../Extensions/ClaimsPrincipalExtensions.cs | 0 .../Extensions/HttpContextExtensions.cs | 0 .../Modules.Common.Shared.csproj} | 4 +- .../Multitenancy/FshTenantInfo.cs | 0 .../Multitenancy/IFshTenantInfo.cs | 0 .../Multitenancy/MultiTenancyConstants.cs | 0 .../Modules/Identity/Identity.csproj | 17 --- .../Dtos/RoleDto.cs | 0 .../Dtos/TokenDto.cs | 0 .../Dtos/UserDto.cs | 0 .../Dtos/UserRoleDto.cs | 0 .../IdentityModuleConstants.cs | 2 +- .../Modules.Identity.Contracts.csproj} | 6 +- .../UpdatePermissionsCommand.cs | 4 +- .../v1/Roles/UpsertRole/UpsertRoleCommand.cs | 0 .../RefreshToken/RefreshTokenCommand.cs | 0 .../RefreshTokenCommandResponse.cs | 0 .../TokenGeneration/TokenGenerationCommand.cs | 0 .../TokenGenerationCommandResponse.cs | 0 .../AssignUserRoles/AssignUserRolesCommand.cs | 0 .../AssignUserRolesCommandResponse.cs | 0 .../ChangePassword/ChangePasswordCommand.cs | 0 .../ForgotPassword/ForgotPasswordCommand.cs | 0 .../Users/RegisterUser/RegisterUserCommand.cs | 0 .../RegisterUser/RegisterUserResponse.cs | 0 .../ResetPassword/ResetPasswordCommand.cs | 0 .../ToggleUserStatusCommand.cs | 0 .../v1/Users/UpdateUser/UpdateUserCommand.cs | 0 .../Authorization/CurrentUserMiddleware.cs | 0 .../Authorization/Jwt/Extensions.cs | 0 .../PathAwareAuthorizationHandler.cs | 0 .../PermissionAuthorizationRequirement.cs | 0 ...quiredPermissionAuthorizationExtensions.cs | 0 .../RequiredPermissionAuthorizationHandler.cs | 0 .../Data/IdentityConfigurations.cs | 2 +- .../Data/IdentityDbContext.cs | 0 .../Data/IdentityDbInitializer.cs | 0 .../Features/v1/RoleClaims/FshRoleClaim.cs | 0 .../v1/Roles/DeleteRole/DeleteRoleEndpoint.cs | 0 .../Features/v1/Roles/FshRole.cs | 0 .../v1/Roles/GetRole/GetRoleEndpoint.cs | 0 .../GetRolePermissionsEndpoint.cs | 0 .../v1/Roles/GetRoles/GetRolesEndpoint.cs | 0 .../Features/v1/Roles/RoleService.cs | 0 .../UpdatePermissionsCommandValidator.cs | 1 + .../UpdateRolePermissionsEndpoint.cs | 2 +- .../UpsertRole/CreateOrUpdateRoleEndpoint.cs | 0 .../UpsertRole/UpsertRoleCommandValidator.cs | 0 .../RefreshTokenCommandHandler.cs | 0 .../RefreshTokenCommandValidator.cs | 0 .../RefreshToken/RefreshTokenEndpoint.cs | 0 .../TokenGenerationCommandHandler.cs | 0 .../TokenGenerationCommandValidator.cs | 0 .../TokenGenerationEndpoint.cs | 0 .../AssignUserRolesCommandHandler.cs | 0 .../AssignUserRolesEndpoint.cs | 0 .../ChangePassword/ChangePasswordEndpoint.cs | 0 .../ChangePassword/ChangePasswordValidator.cs | 0 .../ConfirmEmail/ConfirmEmailEndpoint.cs | 0 .../v1/Users/DeleteUser/DeleteUserEndpoint.cs | 0 .../ForgotPasswordCommandValidator.cs | 0 .../ForgotPassword/ForgotPasswordEndpoint.cs | 0 .../Features/v1/Users/FshUser.cs | 0 .../v1/Users/GetUser/GetUserEndpoint.cs | 0 .../GetUserPermissionsEndpoint.cs | 0 .../GetUserProfile/GetUserProfileEndpoint.cs | 0 .../GetUserRoles/GetUserRolesEndpoint.cs | 0 .../v1/Users/GetUsers/GetUsersListEndpoint.cs | 0 .../RegisterUser/RegisterUserEndpoint.cs | 0 .../ResetPasswordCommandValidator.cs | 0 .../ResetPassword/ResetPasswordEndpoint.cs | 0 .../SelfRegisterUserEndpoint.cs | 0 .../ToggleUserStatusEndpoint.cs | 0 .../UpdateUser/UpdateUserCommandValidator.cs | 0 .../v1/Users/UpdateUser/UpdateUserEndpoint.cs | 0 .../Features/v1/Users/UserImageValidator.cs | 0 .../Identity.Core/Identity.Core.csproj | 0 .../Identity.Endpoints.csproj | 0 .../Identity.Infrastructure.csproj | 0 .../{ => Modules.Identity}/IdentityModule.cs | 2 +- .../Modules.Identity/Modules.Identity.csproj | 17 +++ .../Options/ConfigureJwtBearerOptions.cs | 0 .../Options/JwtOptions.cs | 0 .../Services/CurrentUserService.cs | 0 .../Services/IRoleService.cs | 0 .../Services/ITokenService.cs | 0 .../Services/IUserService.cs | 0 .../Services/TokenService.cs | 0 .../Services/UserService.Password.cs | 0 .../Services/UserService.Permissions.cs | 0 .../Services/UserService.cs | 0 .../Dtos/TenantDto.cs | 0 .../Modules.Tenant.Contracts.csproj} | 6 +- .../TenantConstants.cs | 0 .../ActivateTenant/ActivateTenantCommand.cs | 0 .../ActivateTenantCommandResponse.cs | 0 .../v1/CreateTenant/CreateTenantCommand.cs | 0 .../CreateTenantCommandResponse.cs | 0 .../v1/DisableTenant/DisableTenantCommand.cs | 0 .../DisableTenantCommandResponse.cs | 0 .../v1/GetTenantById/GetTenantByIdQuery.cs | 0 .../GetTenantByIdQueryResponse.cs | 0 .../v1/GetTenants/GetTenantsQuery.cs | 0 .../v1/GetTenants/GetTenantsQueryResponse.cs | 0 .../v1/UpgradeTenant/UpgradeTenantCommand.cs | 0 .../UpgradeTenantCommandResponse.cs | 0 .../Data/TenantDbContext.cs | 0 .../Tenant/{ => Modules.Tenant}/Extensions.cs | 0 .../ActivateTenantCommandHandler.cs | 0 .../ActivateTenantCommandValidator.cs | 0 .../ActivateTenant/ActivateTenantEndpoint.cs | 0 .../CreateTenantCommandHandler.cs | 0 .../CreateTenantCommandValidator.cs | 0 .../v1/CreateTenant/CreateTenantEndpoint.cs | 0 .../DisableTenantCommandHandler.cs | 0 .../DisableTenantCommandValidator.cs | 0 .../v1/DisableTenant/DisableTenantEndpoint.cs | 0 .../v1/GetTenantById/GetTenantByIdEndpoint.cs | 0 .../GetTenantByIdQueryHandler.cs | 0 .../v1/GetTenants/GetTenantsEndpoint.cs | 0 .../v1/GetTenants/GetTenantsQueryHandler.cs | 0 .../UpgradeTenantCommandHandler.cs | 0 .../UpgradeTenantCommandValidator.cs | 0 .../v1/UpgradeTenant/UpgradeTenantEndpoint.cs | 0 .../Modules.Tenant/Modules.Tenant.csproj | 20 +++ .../Services/ITenantService.cs | 0 .../Services/TenantService.cs | 0 .../{ => Modules.Tenant}/TenantModule.cs | 0 src/framework/Modules/Tenant/Tenant.csproj | 20 --- .../PlayGround.Api/PlayGround.Api.csproj | 11 +- .../PostgreSQL/Migrations.PostgreSQL.csproj | 9 +- src/framework/scripts/pack.ps1 | 11 ++ 277 files changed, 176 insertions(+), 138 deletions(-) delete mode 100644 src/framework/Modules/Auditing/Auditing.csproj rename src/framework/Modules/{Auditing.Contracts => Auditing/Modules.Auditing.Contracts}/AuditingConstants.cs (100%) rename src/framework/Modules/{Auditing.Contracts => Auditing/Modules.Auditing.Contracts}/Dtos/TrailDto.cs (100%) rename src/framework/Modules/{Auditing.Contracts => Auditing/Modules.Auditing.Contracts}/Enums/AuditOperation.cs (100%) rename src/framework/Modules/{Auditing.Contracts => Auditing/Modules.Auditing.Contracts}/Events/IntegrationEvents/AuditPublishedEvent.cs (100%) rename src/framework/Modules/{Auditing.Contracts/Auditing.Contracts.csproj => Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj} (77%) rename src/framework/Modules/{Auditing.Contracts => Auditing/Modules.Auditing.Contracts}/v1/GetUserTrails/GetUserTrailsQuery.cs (100%) rename src/framework/Modules/{Auditing.Contracts => Auditing/Modules.Auditing.Contracts}/v1/GetUserTrails/GetUserTrailsQueryResponse.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/AuditingModule.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Data/AuditingConfiguration.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Data/AuditingDbContext.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Data/AuditingDbInitializer.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Data/IAuditingDbContext.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Data/Interceptors/AuditInterceptor.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/EventHandlers/AuditPublishedIntegrationEventHandler.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Features/Entities/Trail.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Mappings/TrailMappings.cs (100%) create mode 100644 src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Services/AuditService.cs (100%) rename src/framework/Modules/Auditing/{ => Modules.Auditing}/Services/IAuditService.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Caching/CacheOptions.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Caching/CacheServiceExtensions.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Caching/ICacheService.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Domain/AuditableEntity.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Domain/BaseEntity.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Domain/Contracts/IAggregateRoot.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Domain/Contracts/IAuditable.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Domain/Contracts/IEntity.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Domain/Contracts/ISoftDeletable.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Exceptions/CustomException.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Exceptions/ForbiddenException.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Exceptions/NotFoundException.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Exceptions/UnauthorizedException.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/ExecutionContext/ICurrentUser.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/ExecutionContext/ICurrentUserInitializer.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/FshCore.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Helpers/JsonHelpers.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Jobs/IJobService.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Mail/IMailService.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Mail/MailOptions.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Mail/MailRequest.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/CQRS/ICommand.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/CQRS/ICommandDispatcher.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/CQRS/ICommandHandler.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/CQRS/IQuery.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/CQRS/IQueryDispatcher.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/CQRS/IQueryHandler.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/CQRS/IRequest.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/Events/AppEvent.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/Events/IEvent.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/Events/IEventHandler.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/Events/IEventPublisher.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/Events/INotification.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Messaging/Events/Notification.cs (100%) rename src/framework/{Core/Core.csproj => Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj} (80%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Modules/ICoreModule.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Origin/OriginOptions.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/BaseFilter.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/Filter.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/FilterLogic.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/FilterOperator.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/IPageRequest.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/IPagedList.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/PagedList.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/PaginationFilter.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/PaginationFilterExtensions.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Paging/Search.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Persistence/DatabaseOptions.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Persistence/IConnectionStringValidator.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Persistence/IDbInitializer.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Persistence/IRepository.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Specifications/EntitiesByBaseFilterSpec.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Specifications/EntitiesByPaginationFilterSpec.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Specifications/SpecificationBuilderExtensions.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Storage/FileType.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Storage/FileUploadRequest.cs (100%) rename src/framework/{Core => Modules/Common/Modules.Common.Core}/Storage/IStorageService.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Caching/DistributedCacheService.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Caching/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Common/Extensions/EnumExtensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Common/Extensions/RegexExtensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Constants/QueryStringKeys.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Cors/CorsOptions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Cors/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Exceptions/CustomExceptionHandler.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Extensions/PagedListExtensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Extensions/RepositoryExtensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/FshInfrastructure.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/HealthChecks/HealthCheckEndpoint.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/HealthChecks/HealthCheckMiddleware.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Jobs/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Jobs/FshJobActivator.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Jobs/FshJobFilter.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Jobs/HangfireCustomBasicAuthenticationFilter.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Jobs/HangfireOptions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Jobs/HangfireService.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Jobs/LogJobFilter.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Logging/Serilog/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Logging/Serilog/StaticLogger.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Mail/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Mail/SmtpMailService.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/CQRS/CommandDispatcher.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/CQRS/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/CQRS/QueryDispatcher.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/CQRS/Validation/CommandValidation.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/CQRS/Validation/QueryValidation.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/CQRS/Validation/ValidationHelper.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/Events/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Messaging/Events/InMemoryEventPublisher.cs (100%) rename src/framework/{Infrastructure/Infrastructure.csproj => Modules/Common/Modules.Common.Infrastructure/Modules.Common.Infrastructure.csproj} (90%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Modules/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Modules/IFrameworkModule.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Modules/IModule.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/OpenApi/BearerSecuritySchemeTransformer.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/OpenApi/ConfigureSwaggerOptions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/OpenApi/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/OpenApi/SwaggerDefaultValues.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Persistence/AppendGlobalQueryFilterExtension.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Persistence/DbProviders.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Persistence/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Persistence/FshDbContext.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Persistence/Services/ConnectionStringValidator.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/RateLimit/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/RateLimit/RateLimitOptions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/SecurityHeaders/Extensions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/SecurityHeaders/SecurityHeaderOptions.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/SecurityHeaders/SecurityHeaders.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Storage/LocalStorageService.cs (100%) rename src/framework/{Infrastructure => Modules/Common/Modules.Common.Infrastructure}/Storage/StorageServiceRegistration.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Authorization/CustomClaims.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Authorization/EndpointExtensions.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Authorization/RequiredPermissionAttribute.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Constants/AuthenticationConstants.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Constants/FshActions.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Constants/FshClaims.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Constants/FshPermissions.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Constants/FshResources.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Constants/FshRoles.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Constants/TenantConstants.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Extensions/ClaimsPrincipalExtensions.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Extensions/HttpContextExtensions.cs (100%) rename src/framework/{Shared/Shared.csproj => Modules/Common/Modules.Common.Shared/Modules.Common.Shared.csproj} (68%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Multitenancy/FshTenantInfo.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Multitenancy/IFshTenantInfo.cs (100%) rename src/framework/{Shared => Modules/Common/Modules.Common.Shared}/Multitenancy/MultiTenancyConstants.cs (100%) delete mode 100644 src/framework/Modules/Identity/Identity.csproj rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/Dtos/RoleDto.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/Dtos/TokenDto.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/Dtos/UserDto.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/Dtos/UserRoleDto.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/IdentityModuleConstants.cs (71%) rename src/framework/Modules/{Tenant.Contracts/Tenant.Contracts.csproj => Identity/Modules.Identity.Contracts/Modules.Identity.Contracts.csproj} (55%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs (65%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Roles/UpsertRole/UpsertRoleCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Tokens/RefreshToken/RefreshTokenCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/ChangePassword/ChangePasswordCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/ForgotPassword/ForgotPasswordCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/RegisterUser/RegisterUserCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/RegisterUser/RegisterUserResponse.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/ResetPassword/ResetPasswordCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs (100%) rename src/framework/Modules/{Identity.Contracts => Identity/Modules.Identity.Contracts}/v1/Users/UpdateUser/UpdateUserCommand.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Authorization/CurrentUserMiddleware.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Authorization/Jwt/Extensions.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Authorization/PathAwareAuthorizationHandler.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Authorization/PermissionAuthorizationRequirement.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Authorization/RequiredPermissionAuthorizationExtensions.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Authorization/RequiredPermissionAuthorizationHandler.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Data/IdentityConfigurations.cs (98%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Data/IdentityDbContext.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Data/IdentityDbInitializer.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/RoleClaims/FshRoleClaim.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/FshRole.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/GetRole/GetRoleEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/RoleService.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs (83%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs (94%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/FshUser.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/GetUser/GetUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Features/v1/Users/UserImageValidator.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Identity.Core/Identity.Core.csproj (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Identity.Endpoints/Identity.Endpoints.csproj (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Identity.Infrastructure/Identity.Infrastructure.csproj (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/IdentityModule.cs (98%) create mode 100644 src/framework/Modules/Identity/Modules.Identity/Modules.Identity.csproj rename src/framework/Modules/Identity/{ => Modules.Identity}/Options/ConfigureJwtBearerOptions.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Options/JwtOptions.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/CurrentUserService.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/IRoleService.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/ITokenService.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/IUserService.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/TokenService.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/UserService.Password.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/UserService.Permissions.cs (100%) rename src/framework/Modules/Identity/{ => Modules.Identity}/Services/UserService.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/Dtos/TenantDto.cs (100%) rename src/framework/Modules/{Identity.Contracts/Identity.Contracts.csproj => Tenant/Modules.Tenant.Contracts/Modules.Tenant.Contracts.csproj} (55%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/TenantConstants.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/ActivateTenant/ActivateTenantCommand.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/ActivateTenant/ActivateTenantCommandResponse.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/CreateTenant/CreateTenantCommand.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/CreateTenant/CreateTenantCommandResponse.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/DisableTenant/DisableTenantCommand.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/DisableTenant/DisableTenantCommandResponse.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/GetTenantById/GetTenantByIdQuery.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/GetTenantById/GetTenantByIdQueryResponse.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/GetTenants/GetTenantsQuery.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/GetTenants/GetTenantsQueryResponse.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/UpgradeTenant/UpgradeTenantCommand.cs (100%) rename src/framework/Modules/{Tenant.Contracts => Tenant/Modules.Tenant.Contracts}/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Data/TenantDbContext.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Extensions.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/CreateTenant/CreateTenantCommandHandler.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/CreateTenant/CreateTenantCommandValidator.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/CreateTenant/CreateTenantEndpoint.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/DisableTenant/DisableTenantCommandHandler.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/DisableTenant/DisableTenantCommandValidator.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/DisableTenant/DisableTenantEndpoint.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/GetTenants/GetTenantsEndpoint.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/GetTenants/GetTenantsQueryHandler.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs (100%) create mode 100644 src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Services/ITenantService.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/Services/TenantService.cs (100%) rename src/framework/Modules/Tenant/{ => Modules.Tenant}/TenantModule.cs (100%) delete mode 100644 src/framework/Modules/Tenant/Tenant.csproj create mode 100644 src/framework/scripts/pack.ps1 diff --git a/src/framework/Directory.Build.props b/src/framework/Directory.Build.props index 30bad8c2b..cff018a8a 100644 --- a/src/framework/Directory.Build.props +++ b/src/framework/Directory.Build.props @@ -33,4 +33,16 @@ runtime; build; native; contentfiles; analyzers + + + + Mukesh Murugan + FullStackHero + 3.0.0 + https://github.com/fullstackhero/dotnet-starter-kit + FSH;Modular;CQRS;VerticalSlice + + + true + diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index ef8507d6d..abfb177ad 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -3,26 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Common.Infrastructure", "Modules\Common\Modules.Common.Infrastructure\Modules.Common.Infrastructure.csproj", "{60DF219E-E1EB-428E-BB1F-F0342D42699F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{60DF219E-E1EB-428E-BB1F-F0342D42699F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{09380C15-F138-4305-A595-F4C7E16B6E78}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Common.Shared", "Modules\Common\Modules.Common.Shared\Modules.Common.Shared.csproj", "{09380C15-F138-4305-A595-F4C7E16B6E78}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing", "Modules\Auditing\Auditing.csproj", "{BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auditing.Contracts", "Modules\Auditing.Contracts\Auditing.Contracts.csproj", "{E39A5A4F-D453-A6A2-CA94-468FD795246C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity", "Modules\Identity\Identity.csproj", "{CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Contracts", "Modules\Identity.Contracts\Identity.Contracts.csproj", "{201606BA-48CE-42F0-B31F-596187F40B2F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant", "Modules\Tenant\Tenant.csproj", "{27806993-447E-9781-647B-06D3F4AC834A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tenant.Contracts", "Modules\Tenant.Contracts\Tenant.Contracts.csproj", "{5324A0FF-DBB9-440C-80C2-4891EC719155}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -32,22 +18,38 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PlayGround", "PlayGround", "{C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrations.PostgreSQL", "playground\migrations\PostgreSQL\Migrations.PostgreSQL.csproj", "{EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrations.PostgreSQL", "PlayGround\Migrations\PostgreSQL\Migrations.PostgreSQL.csproj", "{EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayGround.Api", "playground\PlayGround.Api\PlayGround.Api.csproj", "{2527B9BA-2168-ED23-7E12-CF3C7C901279}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayGround.Api", "PlayGround\PlayGround.Api\PlayGround.Api.csproj", "{2527B9BA-2168-ED23-7E12-CF3C7C901279}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{83139AD6-D37E-4209-84A2-5E9023CEDA78}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tenant", "Tenant", "{297D1E34-BA90-4B75-80F4-646CF1FF59CC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Tenant", "Modules\Tenant\Modules.Tenant\Modules.Tenant.csproj", "{FE8B966D-94E8-EF2D-535B-DC58B1D93B2C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Tenant.Contracts", "Modules\Tenant\Modules.Tenant.Contracts\Modules.Tenant.Contracts.csproj", "{13FDC8C1-8926-DBD6-4915-885E6B5067C2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Identity", "Identity", "{020A76FA-D28D-48AA-AFAF-D89E3FE55327}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Identity", "Modules\Identity\Modules.Identity\Modules.Identity.csproj", "{A3A85996-F456-91C2-FABA-DD56D9ECCFE0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Identity.Contracts", "Modules\Identity\Modules.Identity.Contracts\Modules.Identity.Contracts.csproj", "{14E87A21-A0F3-867D-9628-863DF0EFC8B0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Common.Core", "Modules\Common\Modules.Common.Core\Modules.Common.Core.csproj", "{0069E711-9C02-C4FC-1C3D-84B5BE0D0998}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auditing", "Auditing", "{C39F3653-FC44-4E54-A13F-ECE30DDBE888}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Auditing", "Modules\Auditing\Modules.Auditing\Modules.Auditing.csproj", "{A47D120F-EA39-7479-5FF1-E8F0B9524F1B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Auditing.Contracts", "Modules\Auditing\Modules.Auditing.Contracts\Modules.Auditing.Contracts.csproj", "{84460CBC-D11D-D584-6F3C-EEDC6966689F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45}.Release|Any CPU.Build.0 = Release|Any CPU {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Debug|Any CPU.Build.0 = Debug|Any CPU {60DF219E-E1EB-428E-BB1F-F0342D42699F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -56,30 +58,6 @@ Global {09380C15-F138-4305-A595-F4C7E16B6E78}.Debug|Any CPU.Build.0 = Debug|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.ActiveCfg = Release|Any CPU {09380C15-F138-4305-A595-F4C7E16B6E78}.Release|Any CPU.Build.0 = Release|Any CPU - {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B}.Release|Any CPU.Build.0 = Release|Any CPU - {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E39A5A4F-D453-A6A2-CA94-468FD795246C}.Release|Any CPU.Build.0 = Release|Any CPU - {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD}.Release|Any CPU.Build.0 = Release|Any CPU - {201606BA-48CE-42F0-B31F-596187F40B2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {201606BA-48CE-42F0-B31F-596187F40B2F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {201606BA-48CE-42F0-B31F-596187F40B2F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {201606BA-48CE-42F0-B31F-596187F40B2F}.Release|Any CPU.Build.0 = Release|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27806993-447E-9781-647B-06D3F4AC834A}.Release|Any CPU.Build.0 = Release|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5324A0FF-DBB9-440C-80C2-4891EC719155}.Release|Any CPU.Build.0 = Release|Any CPU {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -88,22 +66,54 @@ Global {2527B9BA-2168-ED23-7E12-CF3C7C901279}.Debug|Any CPU.Build.0 = Debug|Any CPU {2527B9BA-2168-ED23-7E12-CF3C7C901279}.Release|Any CPU.ActiveCfg = Release|Any CPU {2527B9BA-2168-ED23-7E12-CF3C7C901279}.Release|Any CPU.Build.0 = Release|Any CPU + {FE8B966D-94E8-EF2D-535B-DC58B1D93B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE8B966D-94E8-EF2D-535B-DC58B1D93B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE8B966D-94E8-EF2D-535B-DC58B1D93B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE8B966D-94E8-EF2D-535B-DC58B1D93B2C}.Release|Any CPU.Build.0 = Release|Any CPU + {13FDC8C1-8926-DBD6-4915-885E6B5067C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13FDC8C1-8926-DBD6-4915-885E6B5067C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13FDC8C1-8926-DBD6-4915-885E6B5067C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13FDC8C1-8926-DBD6-4915-885E6B5067C2}.Release|Any CPU.Build.0 = Release|Any CPU + {A3A85996-F456-91C2-FABA-DD56D9ECCFE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3A85996-F456-91C2-FABA-DD56D9ECCFE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3A85996-F456-91C2-FABA-DD56D9ECCFE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3A85996-F456-91C2-FABA-DD56D9ECCFE0}.Release|Any CPU.Build.0 = Release|Any CPU + {14E87A21-A0F3-867D-9628-863DF0EFC8B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14E87A21-A0F3-867D-9628-863DF0EFC8B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14E87A21-A0F3-867D-9628-863DF0EFC8B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14E87A21-A0F3-867D-9628-863DF0EFC8B0}.Release|Any CPU.Build.0 = Release|Any CPU + {0069E711-9C02-C4FC-1C3D-84B5BE0D0998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0069E711-9C02-C4FC-1C3D-84B5BE0D0998}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0069E711-9C02-C4FC-1C3D-84B5BE0D0998}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0069E711-9C02-C4FC-1C3D-84B5BE0D0998}.Release|Any CPU.Build.0 = Release|Any CPU + {A47D120F-EA39-7479-5FF1-E8F0B9524F1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A47D120F-EA39-7479-5FF1-E8F0B9524F1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A47D120F-EA39-7479-5FF1-E8F0B9524F1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A47D120F-EA39-7479-5FF1-E8F0B9524F1B}.Release|Any CPU.Build.0 = Release|Any CPU + {84460CBC-D11D-D584-6F3C-EEDC6966689F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84460CBC-D11D-D584-6F3C-EEDC6966689F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84460CBC-D11D-D584-6F3C-EEDC6966689F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84460CBC-D11D-D584-6F3C-EEDC6966689F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {9DAFE9BE-B4A7-422E-988C-5CB1A94DFC45} = {83139AD6-D37E-4209-84A2-5E9023CEDA78} {60DF219E-E1EB-428E-BB1F-F0342D42699F} = {83139AD6-D37E-4209-84A2-5E9023CEDA78} {09380C15-F138-4305-A595-F4C7E16B6E78} = {83139AD6-D37E-4209-84A2-5E9023CEDA78} - {BC5BA3BE-DC03-9683-B6EC-16B8DD811B9B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {E39A5A4F-D453-A6A2-CA94-468FD795246C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {CA12AF47-9EA6-4869-9E51-9D318C0FFBAD} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {201606BA-48CE-42F0-B31F-596187F40B2F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {27806993-447E-9781-647B-06D3F4AC834A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {5324A0FF-DBB9-440C-80C2-4891EC719155} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {EEF3610C-BF3C-DA23-0AA8-FED171CE30A2} = {C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B} {2527B9BA-2168-ED23-7E12-CF3C7C901279} = {C9FFFCC7-8CEA-4890-9B6D-91D815A0B04B} + {83139AD6-D37E-4209-84A2-5E9023CEDA78} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {297D1E34-BA90-4B75-80F4-646CF1FF59CC} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {FE8B966D-94E8-EF2D-535B-DC58B1D93B2C} = {297D1E34-BA90-4B75-80F4-646CF1FF59CC} + {13FDC8C1-8926-DBD6-4915-885E6B5067C2} = {297D1E34-BA90-4B75-80F4-646CF1FF59CC} + {020A76FA-D28D-48AA-AFAF-D89E3FE55327} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {A3A85996-F456-91C2-FABA-DD56D9ECCFE0} = {020A76FA-D28D-48AA-AFAF-D89E3FE55327} + {14E87A21-A0F3-867D-9628-863DF0EFC8B0} = {020A76FA-D28D-48AA-AFAF-D89E3FE55327} + {0069E711-9C02-C4FC-1C3D-84B5BE0D0998} = {83139AD6-D37E-4209-84A2-5E9023CEDA78} + {C39F3653-FC44-4E54-A13F-ECE30DDBE888} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {A47D120F-EA39-7479-5FF1-E8F0B9524F1B} = {C39F3653-FC44-4E54-A13F-ECE30DDBE888} + {84460CBC-D11D-D584-6F3C-EEDC6966689F} = {C39F3653-FC44-4E54-A13F-ECE30DDBE888} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} diff --git a/src/framework/Modules/Auditing/Auditing.csproj b/src/framework/Modules/Auditing/Auditing.csproj deleted file mode 100644 index 414a30df9..000000000 --- a/src/framework/Modules/Auditing/Auditing.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - FSH.Framework.Auditing - FSH.Framework.Auditing - - - net9.0 - enable - enable - - - - - - - diff --git a/src/framework/Modules/Auditing.Contracts/AuditingConstants.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/AuditingConstants.cs similarity index 100% rename from src/framework/Modules/Auditing.Contracts/AuditingConstants.cs rename to src/framework/Modules/Auditing/Modules.Auditing.Contracts/AuditingConstants.cs diff --git a/src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Dtos/TrailDto.cs similarity index 100% rename from src/framework/Modules/Auditing.Contracts/Dtos/TrailDto.cs rename to src/framework/Modules/Auditing/Modules.Auditing.Contracts/Dtos/TrailDto.cs diff --git a/src/framework/Modules/Auditing.Contracts/Enums/AuditOperation.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Enums/AuditOperation.cs similarity index 100% rename from src/framework/Modules/Auditing.Contracts/Enums/AuditOperation.cs rename to src/framework/Modules/Auditing/Modules.Auditing.Contracts/Enums/AuditOperation.cs diff --git a/src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs similarity index 100% rename from src/framework/Modules/Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs rename to src/framework/Modules/Auditing/Modules.Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs diff --git a/src/framework/Modules/Auditing.Contracts/Auditing.Contracts.csproj b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj similarity index 77% rename from src/framework/Modules/Auditing.Contracts/Auditing.Contracts.csproj rename to src/framework/Modules/Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj index 5703eb745..08276423a 100644 --- a/src/framework/Modules/Auditing.Contracts/Auditing.Contracts.csproj +++ b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj @@ -4,9 +4,9 @@ FSH.Framework.Auditing.Contracts - + - + diff --git a/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs similarity index 100% rename from src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs rename to src/framework/Modules/Auditing/Modules.Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQuery.cs diff --git a/src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs similarity index 100% rename from src/framework/Modules/Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs rename to src/framework/Modules/Auditing/Modules.Auditing.Contracts/v1/GetUserTrails/GetUserTrailsQueryResponse.cs diff --git a/src/framework/Modules/Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs similarity index 100% rename from src/framework/Modules/Auditing/AuditingModule.cs rename to src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs diff --git a/src/framework/Modules/Auditing/Data/AuditingConfiguration.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingConfiguration.cs similarity index 100% rename from src/framework/Modules/Auditing/Data/AuditingConfiguration.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingConfiguration.cs diff --git a/src/framework/Modules/Auditing/Data/AuditingDbContext.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs similarity index 100% rename from src/framework/Modules/Auditing/Data/AuditingDbContext.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs diff --git a/src/framework/Modules/Auditing/Data/AuditingDbInitializer.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbInitializer.cs similarity index 100% rename from src/framework/Modules/Auditing/Data/AuditingDbInitializer.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbInitializer.cs diff --git a/src/framework/Modules/Auditing/Data/IAuditingDbContext.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/IAuditingDbContext.cs similarity index 100% rename from src/framework/Modules/Auditing/Data/IAuditingDbContext.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Data/IAuditingDbContext.cs diff --git a/src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs similarity index 100% rename from src/framework/Modules/Auditing/Data/Interceptors/AuditInterceptor.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs diff --git a/src/framework/Modules/Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs b/src/framework/Modules/Auditing/Modules.Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs similarity index 100% rename from src/framework/Modules/Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs rename to src/framework/Modules/Auditing/Modules.Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs diff --git a/src/framework/Modules/Auditing/Features/Entities/Trail.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/Entities/Trail.cs similarity index 100% rename from src/framework/Modules/Auditing/Features/Entities/Trail.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Features/Entities/Trail.cs diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs similarity index 100% rename from src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs similarity index 100% rename from src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs diff --git a/src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs similarity index 100% rename from src/framework/Modules/Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs diff --git a/src/framework/Modules/Auditing/Mappings/TrailMappings.cs b/src/framework/Modules/Auditing/Modules.Auditing/Mappings/TrailMappings.cs similarity index 100% rename from src/framework/Modules/Auditing/Mappings/TrailMappings.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Mappings/TrailMappings.cs diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj b/src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj new file mode 100644 index 000000000..c97975449 --- /dev/null +++ b/src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj @@ -0,0 +1,20 @@ + + + FSH.Framework.Auditing + FSH.Framework.Auditing + + + FSH.Framework.Auditing + Auditing module for FullStackHero + + + net9.0 + enable + enable + + + + + + + diff --git a/src/framework/Modules/Auditing/Services/AuditService.cs b/src/framework/Modules/Auditing/Modules.Auditing/Services/AuditService.cs similarity index 100% rename from src/framework/Modules/Auditing/Services/AuditService.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Services/AuditService.cs diff --git a/src/framework/Modules/Auditing/Services/IAuditService.cs b/src/framework/Modules/Auditing/Modules.Auditing/Services/IAuditService.cs similarity index 100% rename from src/framework/Modules/Auditing/Services/IAuditService.cs rename to src/framework/Modules/Auditing/Modules.Auditing/Services/IAuditService.cs diff --git a/src/framework/Core/Caching/CacheOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheOptions.cs similarity index 100% rename from src/framework/Core/Caching/CacheOptions.cs rename to src/framework/Modules/Common/Modules.Common.Core/Caching/CacheOptions.cs diff --git a/src/framework/Core/Caching/CacheServiceExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs similarity index 100% rename from src/framework/Core/Caching/CacheServiceExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs diff --git a/src/framework/Core/Caching/ICacheService.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/ICacheService.cs similarity index 100% rename from src/framework/Core/Caching/ICacheService.cs rename to src/framework/Modules/Common/Modules.Common.Core/Caching/ICacheService.cs diff --git a/src/framework/Core/Domain/AuditableEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs similarity index 100% rename from src/framework/Core/Domain/AuditableEntity.cs rename to src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs diff --git a/src/framework/Core/Domain/BaseEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs similarity index 100% rename from src/framework/Core/Domain/BaseEntity.cs rename to src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs diff --git a/src/framework/Core/Domain/Contracts/IAggregateRoot.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs similarity index 100% rename from src/framework/Core/Domain/Contracts/IAggregateRoot.cs rename to src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs diff --git a/src/framework/Core/Domain/Contracts/IAuditable.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs similarity index 100% rename from src/framework/Core/Domain/Contracts/IAuditable.cs rename to src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs diff --git a/src/framework/Core/Domain/Contracts/IEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs similarity index 100% rename from src/framework/Core/Domain/Contracts/IEntity.cs rename to src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs diff --git a/src/framework/Core/Domain/Contracts/ISoftDeletable.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs similarity index 100% rename from src/framework/Core/Domain/Contracts/ISoftDeletable.cs rename to src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs diff --git a/src/framework/Core/Exceptions/CustomException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs similarity index 100% rename from src/framework/Core/Exceptions/CustomException.cs rename to src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs diff --git a/src/framework/Core/Exceptions/ForbiddenException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs similarity index 100% rename from src/framework/Core/Exceptions/ForbiddenException.cs rename to src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs diff --git a/src/framework/Core/Exceptions/NotFoundException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs similarity index 100% rename from src/framework/Core/Exceptions/NotFoundException.cs rename to src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs diff --git a/src/framework/Core/Exceptions/UnauthorizedException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs similarity index 100% rename from src/framework/Core/Exceptions/UnauthorizedException.cs rename to src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs diff --git a/src/framework/Core/ExecutionContext/ICurrentUser.cs b/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUser.cs similarity index 100% rename from src/framework/Core/ExecutionContext/ICurrentUser.cs rename to src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUser.cs diff --git a/src/framework/Core/ExecutionContext/ICurrentUserInitializer.cs b/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUserInitializer.cs similarity index 100% rename from src/framework/Core/ExecutionContext/ICurrentUserInitializer.cs rename to src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUserInitializer.cs diff --git a/src/framework/Core/FshCore.cs b/src/framework/Modules/Common/Modules.Common.Core/FshCore.cs similarity index 100% rename from src/framework/Core/FshCore.cs rename to src/framework/Modules/Common/Modules.Common.Core/FshCore.cs diff --git a/src/framework/Core/Helpers/JsonHelpers.cs b/src/framework/Modules/Common/Modules.Common.Core/Helpers/JsonHelpers.cs similarity index 100% rename from src/framework/Core/Helpers/JsonHelpers.cs rename to src/framework/Modules/Common/Modules.Common.Core/Helpers/JsonHelpers.cs diff --git a/src/framework/Core/Jobs/IJobService.cs b/src/framework/Modules/Common/Modules.Common.Core/Jobs/IJobService.cs similarity index 100% rename from src/framework/Core/Jobs/IJobService.cs rename to src/framework/Modules/Common/Modules.Common.Core/Jobs/IJobService.cs diff --git a/src/framework/Core/Mail/IMailService.cs b/src/framework/Modules/Common/Modules.Common.Core/Mail/IMailService.cs similarity index 100% rename from src/framework/Core/Mail/IMailService.cs rename to src/framework/Modules/Common/Modules.Common.Core/Mail/IMailService.cs diff --git a/src/framework/Core/Mail/MailOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Mail/MailOptions.cs similarity index 100% rename from src/framework/Core/Mail/MailOptions.cs rename to src/framework/Modules/Common/Modules.Common.Core/Mail/MailOptions.cs diff --git a/src/framework/Core/Mail/MailRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Mail/MailRequest.cs similarity index 100% rename from src/framework/Core/Mail/MailRequest.cs rename to src/framework/Modules/Common/Modules.Common.Core/Mail/MailRequest.cs diff --git a/src/framework/Core/Messaging/CQRS/ICommand.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs similarity index 100% rename from src/framework/Core/Messaging/CQRS/ICommand.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs diff --git a/src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs similarity index 100% rename from src/framework/Core/Messaging/CQRS/ICommandDispatcher.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs diff --git a/src/framework/Core/Messaging/CQRS/ICommandHandler.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs similarity index 100% rename from src/framework/Core/Messaging/CQRS/ICommandHandler.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs diff --git a/src/framework/Core/Messaging/CQRS/IQuery.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs similarity index 100% rename from src/framework/Core/Messaging/CQRS/IQuery.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs diff --git a/src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryDispatcher.cs similarity index 100% rename from src/framework/Core/Messaging/CQRS/IQueryDispatcher.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryDispatcher.cs diff --git a/src/framework/Core/Messaging/CQRS/IQueryHandler.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryHandler.cs similarity index 100% rename from src/framework/Core/Messaging/CQRS/IQueryHandler.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryHandler.cs diff --git a/src/framework/Core/Messaging/CQRS/IRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs similarity index 100% rename from src/framework/Core/Messaging/CQRS/IRequest.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs diff --git a/src/framework/Core/Messaging/Events/AppEvent.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/AppEvent.cs similarity index 100% rename from src/framework/Core/Messaging/Events/AppEvent.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/AppEvent.cs diff --git a/src/framework/Core/Messaging/Events/IEvent.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEvent.cs similarity index 100% rename from src/framework/Core/Messaging/Events/IEvent.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEvent.cs diff --git a/src/framework/Core/Messaging/Events/IEventHandler.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventHandler.cs similarity index 100% rename from src/framework/Core/Messaging/Events/IEventHandler.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventHandler.cs diff --git a/src/framework/Core/Messaging/Events/IEventPublisher.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventPublisher.cs similarity index 100% rename from src/framework/Core/Messaging/Events/IEventPublisher.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventPublisher.cs diff --git a/src/framework/Core/Messaging/Events/INotification.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/INotification.cs similarity index 100% rename from src/framework/Core/Messaging/Events/INotification.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/INotification.cs diff --git a/src/framework/Core/Messaging/Events/Notification.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/Notification.cs similarity index 100% rename from src/framework/Core/Messaging/Events/Notification.cs rename to src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/Notification.cs diff --git a/src/framework/Core/Core.csproj b/src/framework/Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj similarity index 80% rename from src/framework/Core/Core.csproj rename to src/framework/Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj index 4761a6bb8..9f6709e0e 100644 --- a/src/framework/Core/Core.csproj +++ b/src/framework/Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj @@ -1,7 +1,7 @@  - FSH.Framework.Core - FSH.Framework.Core + FSH.Modules.Common.Core + FSH.Modules.Common.Core diff --git a/src/framework/Core/Modules/ICoreModule.cs b/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs similarity index 100% rename from src/framework/Core/Modules/ICoreModule.cs rename to src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs diff --git a/src/framework/Core/Origin/OriginOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs similarity index 100% rename from src/framework/Core/Origin/OriginOptions.cs rename to src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs diff --git a/src/framework/Core/Paging/BaseFilter.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/BaseFilter.cs similarity index 100% rename from src/framework/Core/Paging/BaseFilter.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/BaseFilter.cs diff --git a/src/framework/Core/Paging/Filter.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/Filter.cs similarity index 100% rename from src/framework/Core/Paging/Filter.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/Filter.cs diff --git a/src/framework/Core/Paging/FilterLogic.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterLogic.cs similarity index 100% rename from src/framework/Core/Paging/FilterLogic.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/FilterLogic.cs diff --git a/src/framework/Core/Paging/FilterOperator.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterOperator.cs similarity index 100% rename from src/framework/Core/Paging/FilterOperator.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/FilterOperator.cs diff --git a/src/framework/Core/Paging/IPageRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/IPageRequest.cs similarity index 100% rename from src/framework/Core/Paging/IPageRequest.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/IPageRequest.cs diff --git a/src/framework/Core/Paging/IPagedList.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/IPagedList.cs similarity index 100% rename from src/framework/Core/Paging/IPagedList.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/IPagedList.cs diff --git a/src/framework/Core/Paging/PagedList.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/PagedList.cs similarity index 100% rename from src/framework/Core/Paging/PagedList.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/PagedList.cs diff --git a/src/framework/Core/Paging/PaginationFilter.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilter.cs similarity index 100% rename from src/framework/Core/Paging/PaginationFilter.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilter.cs diff --git a/src/framework/Core/Paging/PaginationFilterExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilterExtensions.cs similarity index 100% rename from src/framework/Core/Paging/PaginationFilterExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilterExtensions.cs diff --git a/src/framework/Core/Paging/Search.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/Search.cs similarity index 100% rename from src/framework/Core/Paging/Search.cs rename to src/framework/Modules/Common/Modules.Common.Core/Paging/Search.cs diff --git a/src/framework/Core/Persistence/DatabaseOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs similarity index 100% rename from src/framework/Core/Persistence/DatabaseOptions.cs rename to src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs diff --git a/src/framework/Core/Persistence/IConnectionStringValidator.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IConnectionStringValidator.cs similarity index 100% rename from src/framework/Core/Persistence/IConnectionStringValidator.cs rename to src/framework/Modules/Common/Modules.Common.Core/Persistence/IConnectionStringValidator.cs diff --git a/src/framework/Core/Persistence/IDbInitializer.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IDbInitializer.cs similarity index 100% rename from src/framework/Core/Persistence/IDbInitializer.cs rename to src/framework/Modules/Common/Modules.Common.Core/Persistence/IDbInitializer.cs diff --git a/src/framework/Core/Persistence/IRepository.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs similarity index 100% rename from src/framework/Core/Persistence/IRepository.cs rename to src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs diff --git a/src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs b/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByBaseFilterSpec.cs similarity index 100% rename from src/framework/Core/Specifications/EntitiesByBaseFilterSpec.cs rename to src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByBaseFilterSpec.cs diff --git a/src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs b/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByPaginationFilterSpec.cs similarity index 100% rename from src/framework/Core/Specifications/EntitiesByPaginationFilterSpec.cs rename to src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByPaginationFilterSpec.cs diff --git a/src/framework/Core/Specifications/SpecificationBuilderExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Specifications/SpecificationBuilderExtensions.cs similarity index 100% rename from src/framework/Core/Specifications/SpecificationBuilderExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Core/Specifications/SpecificationBuilderExtensions.cs diff --git a/src/framework/Core/Storage/FileType.cs b/src/framework/Modules/Common/Modules.Common.Core/Storage/FileType.cs similarity index 100% rename from src/framework/Core/Storage/FileType.cs rename to src/framework/Modules/Common/Modules.Common.Core/Storage/FileType.cs diff --git a/src/framework/Core/Storage/FileUploadRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Storage/FileUploadRequest.cs similarity index 100% rename from src/framework/Core/Storage/FileUploadRequest.cs rename to src/framework/Modules/Common/Modules.Common.Core/Storage/FileUploadRequest.cs diff --git a/src/framework/Core/Storage/IStorageService.cs b/src/framework/Modules/Common/Modules.Common.Core/Storage/IStorageService.cs similarity index 100% rename from src/framework/Core/Storage/IStorageService.cs rename to src/framework/Modules/Common/Modules.Common.Core/Storage/IStorageService.cs diff --git a/src/framework/Infrastructure/Caching/DistributedCacheService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs similarity index 100% rename from src/framework/Infrastructure/Caching/DistributedCacheService.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs diff --git a/src/framework/Infrastructure/Caching/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Caching/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs diff --git a/src/framework/Infrastructure/Common/Extensions/EnumExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs similarity index 100% rename from src/framework/Infrastructure/Common/Extensions/EnumExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs diff --git a/src/framework/Infrastructure/Common/Extensions/RegexExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/RegexExtensions.cs similarity index 100% rename from src/framework/Infrastructure/Common/Extensions/RegexExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/RegexExtensions.cs diff --git a/src/framework/Infrastructure/Constants/QueryStringKeys.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Constants/QueryStringKeys.cs similarity index 100% rename from src/framework/Infrastructure/Constants/QueryStringKeys.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Constants/QueryStringKeys.cs diff --git a/src/framework/Infrastructure/Cors/CorsOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/CorsOptions.cs similarity index 100% rename from src/framework/Infrastructure/Cors/CorsOptions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/CorsOptions.cs diff --git a/src/framework/Infrastructure/Cors/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Cors/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/Extensions.cs diff --git a/src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs similarity index 100% rename from src/framework/Infrastructure/Exceptions/CustomExceptionHandler.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs diff --git a/src/framework/Infrastructure/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs diff --git a/src/framework/Infrastructure/Extensions/PagedListExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/PagedListExtensions.cs similarity index 100% rename from src/framework/Infrastructure/Extensions/PagedListExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/PagedListExtensions.cs diff --git a/src/framework/Infrastructure/Extensions/RepositoryExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/RepositoryExtensions.cs similarity index 100% rename from src/framework/Infrastructure/Extensions/RepositoryExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/RepositoryExtensions.cs diff --git a/src/framework/Infrastructure/FshInfrastructure.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/FshInfrastructure.cs similarity index 100% rename from src/framework/Infrastructure/FshInfrastructure.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/FshInfrastructure.cs diff --git a/src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckEndpoint.cs similarity index 100% rename from src/framework/Infrastructure/HealthChecks/HealthCheckEndpoint.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckEndpoint.cs diff --git a/src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckMiddleware.cs similarity index 100% rename from src/framework/Infrastructure/HealthChecks/HealthCheckMiddleware.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckMiddleware.cs diff --git a/src/framework/Infrastructure/Jobs/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Jobs/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs diff --git a/src/framework/Infrastructure/Jobs/FshJobActivator.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobActivator.cs similarity index 100% rename from src/framework/Infrastructure/Jobs/FshJobActivator.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobActivator.cs diff --git a/src/framework/Infrastructure/Jobs/FshJobFilter.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobFilter.cs similarity index 100% rename from src/framework/Infrastructure/Jobs/FshJobFilter.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobFilter.cs diff --git a/src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs similarity index 100% rename from src/framework/Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs diff --git a/src/framework/Infrastructure/Jobs/HangfireOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireOptions.cs similarity index 100% rename from src/framework/Infrastructure/Jobs/HangfireOptions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireOptions.cs diff --git a/src/framework/Infrastructure/Jobs/HangfireService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireService.cs similarity index 100% rename from src/framework/Infrastructure/Jobs/HangfireService.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireService.cs diff --git a/src/framework/Infrastructure/Jobs/LogJobFilter.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/LogJobFilter.cs similarity index 100% rename from src/framework/Infrastructure/Jobs/LogJobFilter.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/LogJobFilter.cs diff --git a/src/framework/Infrastructure/Logging/Serilog/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Logging/Serilog/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs diff --git a/src/framework/Infrastructure/Logging/Serilog/StaticLogger.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/StaticLogger.cs similarity index 100% rename from src/framework/Infrastructure/Logging/Serilog/StaticLogger.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/StaticLogger.cs diff --git a/src/framework/Infrastructure/Mail/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Mail/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs diff --git a/src/framework/Infrastructure/Mail/SmtpMailService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/SmtpMailService.cs similarity index 100% rename from src/framework/Infrastructure/Mail/SmtpMailService.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/SmtpMailService.cs diff --git a/src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/CQRS/CommandDispatcher.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs diff --git a/src/framework/Infrastructure/Messaging/CQRS/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/CQRS/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs diff --git a/src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/QueryDispatcher.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/CQRS/QueryDispatcher.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/QueryDispatcher.cs diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs diff --git a/src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs diff --git a/src/framework/Infrastructure/Messaging/Events/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/Events/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs diff --git a/src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/InMemoryEventPublisher.cs similarity index 100% rename from src/framework/Infrastructure/Messaging/Events/InMemoryEventPublisher.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/InMemoryEventPublisher.cs diff --git a/src/framework/Infrastructure/Infrastructure.csproj b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules.Common.Infrastructure.csproj similarity index 90% rename from src/framework/Infrastructure/Infrastructure.csproj rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Modules.Common.Infrastructure.csproj index 7ec135554..e218998ff 100644 --- a/src/framework/Infrastructure/Infrastructure.csproj +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules.Common.Infrastructure.csproj @@ -1,7 +1,7 @@  - FSH.Framework.Infrastructure - FSH.Framework.Infrastructure + FSH.Modules.Common.Infrastructure + FSH.Modules.Common.Infrastructure @@ -57,7 +57,7 @@ - - + + diff --git a/src/framework/Infrastructure/Modules/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Modules/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs diff --git a/src/framework/Infrastructure/Modules/IFrameworkModule.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs similarity index 100% rename from src/framework/Infrastructure/Modules/IFrameworkModule.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs diff --git a/src/framework/Infrastructure/Modules/IModule.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IModule.cs similarity index 100% rename from src/framework/Infrastructure/Modules/IModule.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IModule.cs diff --git a/src/framework/Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs similarity index 100% rename from src/framework/Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/BearerSecuritySchemeTransformer.cs diff --git a/src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/ConfigureSwaggerOptions.cs similarity index 100% rename from src/framework/Infrastructure/OpenApi/ConfigureSwaggerOptions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/ConfigureSwaggerOptions.cs diff --git a/src/framework/Infrastructure/OpenApi/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/OpenApi/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs diff --git a/src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/SwaggerDefaultValues.cs similarity index 100% rename from src/framework/Infrastructure/OpenApi/SwaggerDefaultValues.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/SwaggerDefaultValues.cs diff --git a/src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs similarity index 100% rename from src/framework/Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs diff --git a/src/framework/Infrastructure/Persistence/DbProviders.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/DbProviders.cs similarity index 100% rename from src/framework/Infrastructure/Persistence/DbProviders.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/DbProviders.cs diff --git a/src/framework/Infrastructure/Persistence/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/Persistence/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs diff --git a/src/framework/Infrastructure/Persistence/FshDbContext.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs similarity index 100% rename from src/framework/Infrastructure/Persistence/FshDbContext.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs diff --git a/src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Services/ConnectionStringValidator.cs similarity index 100% rename from src/framework/Infrastructure/Persistence/Services/ConnectionStringValidator.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Services/ConnectionStringValidator.cs diff --git a/src/framework/Infrastructure/RateLimit/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/RateLimit/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs diff --git a/src/framework/Infrastructure/RateLimit/RateLimitOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/RateLimitOptions.cs similarity index 100% rename from src/framework/Infrastructure/RateLimit/RateLimitOptions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/RateLimitOptions.cs diff --git a/src/framework/Infrastructure/SecurityHeaders/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs similarity index 100% rename from src/framework/Infrastructure/SecurityHeaders/Extensions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs diff --git a/src/framework/Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs similarity index 100% rename from src/framework/Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs diff --git a/src/framework/Infrastructure/SecurityHeaders/SecurityHeaders.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaders.cs similarity index 100% rename from src/framework/Infrastructure/SecurityHeaders/SecurityHeaders.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaders.cs diff --git a/src/framework/Infrastructure/Storage/LocalStorageService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/LocalStorageService.cs similarity index 100% rename from src/framework/Infrastructure/Storage/LocalStorageService.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/LocalStorageService.cs diff --git a/src/framework/Infrastructure/Storage/StorageServiceRegistration.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs similarity index 100% rename from src/framework/Infrastructure/Storage/StorageServiceRegistration.cs rename to src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs diff --git a/src/framework/Shared/Authorization/CustomClaims.cs b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/CustomClaims.cs similarity index 100% rename from src/framework/Shared/Authorization/CustomClaims.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Authorization/CustomClaims.cs diff --git a/src/framework/Shared/Authorization/EndpointExtensions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/EndpointExtensions.cs similarity index 100% rename from src/framework/Shared/Authorization/EndpointExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Authorization/EndpointExtensions.cs diff --git a/src/framework/Shared/Authorization/RequiredPermissionAttribute.cs b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/RequiredPermissionAttribute.cs similarity index 100% rename from src/framework/Shared/Authorization/RequiredPermissionAttribute.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Authorization/RequiredPermissionAttribute.cs diff --git a/src/framework/Shared/Constants/AuthenticationConstants.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/AuthenticationConstants.cs similarity index 100% rename from src/framework/Shared/Constants/AuthenticationConstants.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/AuthenticationConstants.cs diff --git a/src/framework/Shared/Constants/FshActions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshActions.cs similarity index 100% rename from src/framework/Shared/Constants/FshActions.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/FshActions.cs diff --git a/src/framework/Shared/Constants/FshClaims.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshClaims.cs similarity index 100% rename from src/framework/Shared/Constants/FshClaims.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/FshClaims.cs diff --git a/src/framework/Shared/Constants/FshPermissions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshPermissions.cs similarity index 100% rename from src/framework/Shared/Constants/FshPermissions.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/FshPermissions.cs diff --git a/src/framework/Shared/Constants/FshResources.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshResources.cs similarity index 100% rename from src/framework/Shared/Constants/FshResources.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/FshResources.cs diff --git a/src/framework/Shared/Constants/FshRoles.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshRoles.cs similarity index 100% rename from src/framework/Shared/Constants/FshRoles.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/FshRoles.cs diff --git a/src/framework/Shared/Constants/TenantConstants.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs similarity index 100% rename from src/framework/Shared/Constants/TenantConstants.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs diff --git a/src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Extensions/ClaimsPrincipalExtensions.cs similarity index 100% rename from src/framework/Shared/Extensions/ClaimsPrincipalExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Extensions/ClaimsPrincipalExtensions.cs diff --git a/src/framework/Shared/Extensions/HttpContextExtensions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Extensions/HttpContextExtensions.cs similarity index 100% rename from src/framework/Shared/Extensions/HttpContextExtensions.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Extensions/HttpContextExtensions.cs diff --git a/src/framework/Shared/Shared.csproj b/src/framework/Modules/Common/Modules.Common.Shared/Modules.Common.Shared.csproj similarity index 68% rename from src/framework/Shared/Shared.csproj rename to src/framework/Modules/Common/Modules.Common.Shared/Modules.Common.Shared.csproj index b56774d74..48e1551e0 100644 --- a/src/framework/Shared/Shared.csproj +++ b/src/framework/Modules/Common/Modules.Common.Shared/Modules.Common.Shared.csproj @@ -1,7 +1,7 @@  - FSH.Framework.Shared - FSH.Framework.Shared + FSH.Modules.Common.Shared + FSH.Modules.Common.Shared diff --git a/src/framework/Shared/Multitenancy/FshTenantInfo.cs b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs similarity index 100% rename from src/framework/Shared/Multitenancy/FshTenantInfo.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs diff --git a/src/framework/Shared/Multitenancy/IFshTenantInfo.cs b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/IFshTenantInfo.cs similarity index 100% rename from src/framework/Shared/Multitenancy/IFshTenantInfo.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/IFshTenantInfo.cs diff --git a/src/framework/Shared/Multitenancy/MultiTenancyConstants.cs b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/MultiTenancyConstants.cs similarity index 100% rename from src/framework/Shared/Multitenancy/MultiTenancyConstants.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/MultiTenancyConstants.cs diff --git a/src/framework/Modules/Identity/Identity.csproj b/src/framework/Modules/Identity/Identity.csproj deleted file mode 100644 index f7a276acf..000000000 --- a/src/framework/Modules/Identity/Identity.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - FSH.Framework.Identity - FSH.Framework.Identity - - - net9.0 - enable - enable - - - - - - - - diff --git a/src/framework/Modules/Identity.Contracts/Dtos/RoleDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/RoleDto.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/Dtos/RoleDto.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/RoleDto.cs diff --git a/src/framework/Modules/Identity.Contracts/Dtos/TokenDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/TokenDto.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/Dtos/TokenDto.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/TokenDto.cs diff --git a/src/framework/Modules/Identity.Contracts/Dtos/UserDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserDto.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/Dtos/UserDto.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserDto.cs diff --git a/src/framework/Modules/Identity.Contracts/Dtos/UserRoleDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserRoleDto.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/Dtos/UserRoleDto.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserRoleDto.cs diff --git a/src/framework/Modules/Identity.Contracts/IdentityModuleConstants.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/IdentityModuleConstants.cs similarity index 71% rename from src/framework/Modules/Identity.Contracts/IdentityModuleConstants.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/IdentityModuleConstants.cs index 526e267ba..3eec6ae59 100644 --- a/src/framework/Modules/Identity.Contracts/IdentityModuleConstants.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/IdentityModuleConstants.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Identity.Contracts; +namespace FSH.Framework.Modules.Identity.Contracts; public static class IdentityModuleConstants { public const string SchemaName = "identity"; diff --git a/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj b/src/framework/Modules/Identity/Modules.Identity.Contracts/Modules.Identity.Contracts.csproj similarity index 55% rename from src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj rename to src/framework/Modules/Identity/Modules.Identity.Contracts/Modules.Identity.Contracts.csproj index a5cfd6497..968bf187e 100644 --- a/src/framework/Modules/Tenant.Contracts/Tenant.Contracts.csproj +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/Modules.Identity.Contracts.csproj @@ -1,7 +1,7 @@  - FSH.Framework.Tenant.Contracts - FSH.Framework.Tenant.Contracts + FSH.Modules.Identity.Contracts + FSH.Modules.Identity.Contracts net9.0 @@ -9,7 +9,7 @@ enable - + diff --git a/src/framework/Modules/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs similarity index 65% rename from src/framework/Modules/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs index d2aac3b73..1f04d7daa 100644 --- a/src/framework/Modules/Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; +namespace FSH.Framework.Modules.Identity.Contracts.v1.Roles.UpdatePermissions; public class UpdatePermissionsCommand { @@ -10,5 +10,5 @@ public class UpdatePermissionsCommand /// /// The list of permissions to assign to the role. /// - public List Permissions { get; init; } = default!; + public List Permissions { get; init; } = []; } diff --git a/src/framework/Modules/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommandResponse.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommandResponse.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommandResponse.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs diff --git a/src/framework/Modules/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs similarity index 100% rename from src/framework/Modules/Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs rename to src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs diff --git a/src/framework/Modules/Identity/Authorization/CurrentUserMiddleware.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/CurrentUserMiddleware.cs similarity index 100% rename from src/framework/Modules/Identity/Authorization/CurrentUserMiddleware.cs rename to src/framework/Modules/Identity/Modules.Identity/Authorization/CurrentUserMiddleware.cs diff --git a/src/framework/Modules/Identity/Authorization/Jwt/Extensions.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/Jwt/Extensions.cs similarity index 100% rename from src/framework/Modules/Identity/Authorization/Jwt/Extensions.cs rename to src/framework/Modules/Identity/Modules.Identity/Authorization/Jwt/Extensions.cs diff --git a/src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs similarity index 100% rename from src/framework/Modules/Identity/Authorization/PathAwareAuthorizationHandler.cs rename to src/framework/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs diff --git a/src/framework/Modules/Identity/Authorization/PermissionAuthorizationRequirement.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/PermissionAuthorizationRequirement.cs similarity index 100% rename from src/framework/Modules/Identity/Authorization/PermissionAuthorizationRequirement.cs rename to src/framework/Modules/Identity/Modules.Identity/Authorization/PermissionAuthorizationRequirement.cs diff --git a/src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs similarity index 100% rename from src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs rename to src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs diff --git a/src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs similarity index 100% rename from src/framework/Modules/Identity/Authorization/RequiredPermissionAuthorizationHandler.cs rename to src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs diff --git a/src/framework/Modules/Identity/Data/IdentityConfigurations.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityConfigurations.cs similarity index 98% rename from src/framework/Modules/Identity/Data/IdentityConfigurations.cs rename to src/framework/Modules/Identity/Modules.Identity/Data/IdentityConfigurations.cs index 752f3be6d..8b256a434 100644 --- a/src/framework/Modules/Identity/Data/IdentityConfigurations.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityConfigurations.cs @@ -1,8 +1,8 @@ using Finbuckle.MultiTenant; -using FSH.Framework.Identity.Contracts; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; using FSH.Framework.Identity.v1.RoleClaims; +using FSH.Framework.Modules.Identity.Contracts; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/framework/Modules/Identity/Data/IdentityDbContext.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs similarity index 100% rename from src/framework/Modules/Identity/Data/IdentityDbContext.cs rename to src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs diff --git a/src/framework/Modules/Identity/Data/IdentityDbInitializer.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs similarity index 100% rename from src/framework/Modules/Identity/Data/IdentityDbInitializer.cs rename to src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs diff --git a/src/framework/Modules/Identity/Features/v1/RoleClaims/FshRoleClaim.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/RoleClaims/FshRoleClaim.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/RoleClaims/FshRoleClaim.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/RoleClaims/FshRoleClaim.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/FshRole.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/FshRole.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/FshRole.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/FshRole.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/RoleService.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/RoleService.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs similarity index 83% rename from src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs index 555d370e7..dfff18bf2 100644 --- a/src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs @@ -1,4 +1,5 @@ using FluentValidation; +using FSH.Framework.Modules.Identity.Contracts.v1.Roles.UpdatePermissions; namespace FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; public class UpdatePermissionsCommandValidator : AbstractValidator diff --git a/src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs similarity index 94% rename from src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs index bed060b3a..cfa631bbf 100644 --- a/src/framework/Modules/Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs @@ -1,6 +1,6 @@ using FluentValidation; using FSH.Framework.Identity.Core.Roles; -using FSH.Framework.Identity.Endpoints.v1.Roles.UpdatePermissions; +using FSH.Framework.Modules.Identity.Contracts.v1.Roles.UpdatePermissions; using FSH.Framework.Shared.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; diff --git a/src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs diff --git a/src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs diff --git a/src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs diff --git a/src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs diff --git a/src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandValidator.cs diff --git a/src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/FshUser.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/FshUser.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/FshUser.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/FshUser.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs diff --git a/src/framework/Modules/Identity/Features/v1/Users/UserImageValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UserImageValidator.cs similarity index 100% rename from src/framework/Modules/Identity/Features/v1/Users/UserImageValidator.cs rename to src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UserImageValidator.cs diff --git a/src/framework/Modules/Identity/Identity.Core/Identity.Core.csproj b/src/framework/Modules/Identity/Modules.Identity/Identity.Core/Identity.Core.csproj similarity index 100% rename from src/framework/Modules/Identity/Identity.Core/Identity.Core.csproj rename to src/framework/Modules/Identity/Modules.Identity/Identity.Core/Identity.Core.csproj diff --git a/src/framework/Modules/Identity/Identity.Endpoints/Identity.Endpoints.csproj b/src/framework/Modules/Identity/Modules.Identity/Identity.Endpoints/Identity.Endpoints.csproj similarity index 100% rename from src/framework/Modules/Identity/Identity.Endpoints/Identity.Endpoints.csproj rename to src/framework/Modules/Identity/Modules.Identity/Identity.Endpoints/Identity.Endpoints.csproj diff --git a/src/framework/Modules/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/src/framework/Modules/Identity/Modules.Identity/Identity.Infrastructure/Identity.Infrastructure.csproj similarity index 100% rename from src/framework/Modules/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj rename to src/framework/Modules/Identity/Modules.Identity/Identity.Infrastructure/Identity.Infrastructure.csproj diff --git a/src/framework/Modules/Identity/IdentityModule.cs b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs similarity index 98% rename from src/framework/Modules/Identity/IdentityModule.cs rename to src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs index 9da4064f9..1e276b960 100644 --- a/src/framework/Modules/Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs @@ -3,7 +3,6 @@ using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Core.Persistence; using FSH.Framework.Identity.Authorization; -using FSH.Framework.Identity.Contracts; using FSH.Framework.Identity.Core.Roles; using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Identity.Core.Users; @@ -19,6 +18,7 @@ using FSH.Framework.Infrastructure.Identity.Users.Services; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Persistence; +using FSH.Framework.Modules.Identity.Contracts; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; diff --git a/src/framework/Modules/Identity/Modules.Identity/Modules.Identity.csproj b/src/framework/Modules/Identity/Modules.Identity/Modules.Identity.csproj new file mode 100644 index 000000000..6c5af73df --- /dev/null +++ b/src/framework/Modules/Identity/Modules.Identity/Modules.Identity.csproj @@ -0,0 +1,17 @@ + + + FSH.Modules.Identity + FSH.Modules.Identity + + + net9.0 + enable + enable + + + + + + + + diff --git a/src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs b/src/framework/Modules/Identity/Modules.Identity/Options/ConfigureJwtBearerOptions.cs similarity index 100% rename from src/framework/Modules/Identity/Options/ConfigureJwtBearerOptions.cs rename to src/framework/Modules/Identity/Modules.Identity/Options/ConfigureJwtBearerOptions.cs diff --git a/src/framework/Modules/Identity/Options/JwtOptions.cs b/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs similarity index 100% rename from src/framework/Modules/Identity/Options/JwtOptions.cs rename to src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs diff --git a/src/framework/Modules/Identity/Services/CurrentUserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs similarity index 100% rename from src/framework/Modules/Identity/Services/CurrentUserService.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs diff --git a/src/framework/Modules/Identity/Services/IRoleService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/IRoleService.cs similarity index 100% rename from src/framework/Modules/Identity/Services/IRoleService.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/IRoleService.cs diff --git a/src/framework/Modules/Identity/Services/ITokenService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/ITokenService.cs similarity index 100% rename from src/framework/Modules/Identity/Services/ITokenService.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/ITokenService.cs diff --git a/src/framework/Modules/Identity/Services/IUserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/IUserService.cs similarity index 100% rename from src/framework/Modules/Identity/Services/IUserService.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/IUserService.cs diff --git a/src/framework/Modules/Identity/Services/TokenService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs similarity index 100% rename from src/framework/Modules/Identity/Services/TokenService.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs diff --git a/src/framework/Modules/Identity/Services/UserService.Password.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs similarity index 100% rename from src/framework/Modules/Identity/Services/UserService.Password.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs diff --git a/src/framework/Modules/Identity/Services/UserService.Permissions.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs similarity index 100% rename from src/framework/Modules/Identity/Services/UserService.Permissions.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs diff --git a/src/framework/Modules/Identity/Services/UserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs similarity index 100% rename from src/framework/Modules/Identity/Services/UserService.cs rename to src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs diff --git a/src/framework/Modules/Tenant.Contracts/Dtos/TenantDto.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/Dtos/TenantDto.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/Dtos/TenantDto.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/Dtos/TenantDto.cs diff --git a/src/framework/Modules/Identity.Contracts/Identity.Contracts.csproj b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/Modules.Tenant.Contracts.csproj similarity index 55% rename from src/framework/Modules/Identity.Contracts/Identity.Contracts.csproj rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/Modules.Tenant.Contracts.csproj index 70642d051..017e54e1c 100644 --- a/src/framework/Modules/Identity.Contracts/Identity.Contracts.csproj +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/Modules.Tenant.Contracts.csproj @@ -1,7 +1,7 @@  - FSH.Framework.Identity.Contracts - FSH.Framework.Identity.Contracts + FSH.Modules.Tenant.Contracts + FSH.Modules.Tenant.Contracts net9.0 @@ -9,7 +9,7 @@ enable - + diff --git a/src/framework/Modules/Tenant.Contracts/TenantConstants.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/TenantConstants.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommandResponse.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommandResponse.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommandResponse.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs diff --git a/src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs similarity index 100% rename from src/framework/Modules/Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs rename to src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommandResponse.cs diff --git a/src/framework/Modules/Tenant/Data/TenantDbContext.cs b/src/framework/Modules/Tenant/Modules.Tenant/Data/TenantDbContext.cs similarity index 100% rename from src/framework/Modules/Tenant/Data/TenantDbContext.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Data/TenantDbContext.cs diff --git a/src/framework/Modules/Tenant/Extensions.cs b/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs similarity index 100% rename from src/framework/Modules/Tenant/Extensions.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs diff --git a/src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs diff --git a/src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs diff --git a/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs diff --git a/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs diff --git a/src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs diff --git a/src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs diff --git a/src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs similarity index 100% rename from src/framework/Modules/Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj b/src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj new file mode 100644 index 000000000..1a4cdcc05 --- /dev/null +++ b/src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj @@ -0,0 +1,20 @@ + + + FSH.Modules.Tenant + FSH.Modules.Tenant + + + net9.0 + enable + enable + + + + + + + + + + + diff --git a/src/framework/Modules/Tenant/Services/ITenantService.cs b/src/framework/Modules/Tenant/Modules.Tenant/Services/ITenantService.cs similarity index 100% rename from src/framework/Modules/Tenant/Services/ITenantService.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Services/ITenantService.cs diff --git a/src/framework/Modules/Tenant/Services/TenantService.cs b/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs similarity index 100% rename from src/framework/Modules/Tenant/Services/TenantService.cs rename to src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs diff --git a/src/framework/Modules/Tenant/TenantModule.cs b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs similarity index 100% rename from src/framework/Modules/Tenant/TenantModule.cs rename to src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs diff --git a/src/framework/Modules/Tenant/Tenant.csproj b/src/framework/Modules/Tenant/Tenant.csproj deleted file mode 100644 index 3c5e1dd17..000000000 --- a/src/framework/Modules/Tenant/Tenant.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - FSH.Framework.Tenant - FSH.Framework.Tenant - - - net9.0 - enable - enable - - - - - - - - - - - diff --git a/src/framework/playground/PlayGround.Api/PlayGround.Api.csproj b/src/framework/playground/PlayGround.Api/PlayGround.Api.csproj index a893a2000..fc96c817e 100644 --- a/src/framework/playground/PlayGround.Api/PlayGround.Api.csproj +++ b/src/framework/playground/PlayGround.Api/PlayGround.Api.csproj @@ -20,11 +20,12 @@ - - - - - + + + + + + diff --git a/src/framework/playground/migrations/PostgreSQL/Migrations.PostgreSQL.csproj b/src/framework/playground/migrations/PostgreSQL/Migrations.PostgreSQL.csproj index f81aede8e..fd54b3c66 100644 --- a/src/framework/playground/migrations/PostgreSQL/Migrations.PostgreSQL.csproj +++ b/src/framework/playground/migrations/PostgreSQL/Migrations.PostgreSQL.csproj @@ -8,12 +8,11 @@ enable enable - - - - - + + + + diff --git a/src/framework/scripts/pack.ps1 b/src/framework/scripts/pack.ps1 new file mode 100644 index 000000000..5f5a07c9e --- /dev/null +++ b/src/framework/scripts/pack.ps1 @@ -0,0 +1,11 @@ +# Go to repo root from /scripts +Set-Location .. + +Write-Host "Packing local FSH modules..." + +$projects = Get-ChildItem -Recurse -Filter *.csproj ` + | Where-Object { $_.FullName -match "\\framework\\" -and $_.FullName } + +foreach ($proj in $projects) { + dotnet pack $proj.FullName -c Release -o ./nupkgs +} From ff7049085323a703f042e53386f96eec6afb8629 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Fri, 18 Apr 2025 00:19:41 +0530 Subject: [PATCH 42/54] cleanup --- src/framework/Directory.Build.props | 1 - .../Persistence/Extensions.cs | 10 ++++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/framework/Directory.Build.props b/src/framework/Directory.Build.props index cff018a8a..80521c53b 100644 --- a/src/framework/Directory.Build.props +++ b/src/framework/Directory.Build.props @@ -41,7 +41,6 @@ 3.0.0 https://github.com/fullstackhero/dotnet-starter-kit FSH;Modular;CQRS;VerticalSlice - true diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs index d86544817..ec4e9661a 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs @@ -18,8 +18,14 @@ string connectionString builder.ConfigureWarnings(warnings => warnings.Log(RelationalEventId.PendingModelChangesWarning)); return dbProvider.ToUpperInvariant() switch { - DbProviders.PostgreSQL => builder.UseNpgsql(connectionString, e => - e.MigrationsAssembly("FSH.PlayGround.Migrations.PostgreSQL")).EnableSensitiveDataLogging(), + DbProviders.PostgreSQL => builder + .UseNpgsql( + connectionString, + e => + { + e.MigrationsAssembly("FSH.PlayGround.Migrations.PostgreSQL"); + }) + .EnableSensitiveDataLogging(), DbProviders.MSSQL => builder.UseSqlServer(connectionString, e => e.MigrationsAssembly("FSH.Starter.WebApi.Migrations.MSSQL")), _ => throw new InvalidOperationException($"DB Provider {dbProvider} is not supported."), From 66e72a149acf06a14aacde48ac7c1436293a8bb6 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Fri, 18 Apr 2025 00:21:52 +0530 Subject: [PATCH 43/54] cleanup --- .../Auditing/Modules.Auditing.Contracts/AuditingConstants.cs | 2 +- .../Auditing/Modules.Auditing.Contracts/Dtos/TrailDto.cs | 2 +- .../Modules.Auditing.Contracts/Enums/AuditOperation.cs | 2 +- .../Events/IntegrationEvents/AuditPublishedEvent.cs | 2 +- .../Modules/Auditing/Modules.Auditing/AuditingModule.cs | 2 +- .../Auditing/Modules.Auditing/Data/AuditingConfiguration.cs | 2 +- .../Auditing/Modules.Auditing/Data/AuditingDbContext.cs | 2 +- .../Auditing/Modules.Auditing/Data/AuditingDbInitializer.cs | 2 +- .../Auditing/Modules.Auditing/Data/IAuditingDbContext.cs | 2 +- .../Modules.Auditing/Data/Interceptors/AuditInterceptor.cs | 2 +- .../EventHandlers/AuditPublishedIntegrationEventHandler.cs | 2 +- .../Auditing/Modules.Auditing/Features/Entities/Trail.cs | 2 +- .../Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs | 2 +- .../Auditing/Modules.Auditing/Mappings/TrailMappings.cs | 2 +- .../Auditing/Modules.Auditing/Services/AuditService.cs | 2 +- .../Auditing/Modules.Auditing/Services/IAuditService.cs | 2 +- .../Common/Modules.Common.Core/Caching/CacheOptions.cs | 4 ++-- .../Modules.Common.Core/Caching/CacheServiceExtensions.cs | 2 +- .../Common/Modules.Common.Core/Domain/AuditableEntity.cs | 2 +- .../Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs | 2 +- .../Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs | 2 +- .../Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs | 2 +- .../Common/Modules.Common.Core/Domain/Contracts/IEntity.cs | 2 +- .../Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs | 2 +- .../Common/Modules.Common.Core/Exceptions/CustomException.cs | 2 +- .../Modules.Common.Core/Exceptions/ForbiddenException.cs | 2 +- .../Modules.Common.Core/Exceptions/NotFoundException.cs | 2 +- .../Modules.Common.Core/Exceptions/UnauthorizedException.cs | 2 +- .../Modules.Common.Core/ExecutionContext/ICurrentUser.cs | 2 +- .../ExecutionContext/ICurrentUserInitializer.cs | 2 +- src/framework/Modules/Common/Modules.Common.Core/FshCore.cs | 2 +- .../Modules/Common/Modules.Common.Core/Helpers/JsonHelpers.cs | 2 +- .../Modules/Common/Modules.Common.Core/Jobs/IJobService.cs | 2 +- .../Modules/Common/Modules.Common.Core/Mail/IMailService.cs | 2 +- .../Modules/Common/Modules.Common.Core/Mail/MailOptions.cs | 2 +- .../Modules/Common/Modules.Common.Core/Mail/MailRequest.cs | 2 +- .../Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs | 2 +- .../Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs | 2 +- .../Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs | 2 +- .../Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs | 2 +- .../Modules.Common.Core/Messaging/CQRS/IQueryDispatcher.cs | 2 +- .../Modules.Common.Core/Messaging/CQRS/IQueryHandler.cs | 2 +- .../Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs | 2 +- .../Common/Modules.Common.Core/Messaging/Events/AppEvent.cs | 2 +- .../Common/Modules.Common.Core/Messaging/Events/IEvent.cs | 2 +- .../Modules.Common.Core/Messaging/Events/IEventHandler.cs | 2 +- .../Modules.Common.Core/Messaging/Events/IEventPublisher.cs | 2 +- .../Modules.Common.Core/Messaging/Events/INotification.cs | 2 +- .../Modules.Common.Core/Messaging/Events/Notification.cs | 2 +- .../Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs | 2 +- .../Common/Modules.Common.Core/Origin/OriginOptions.cs | 2 +- .../Modules/Common/Modules.Common.Core/Paging/BaseFilter.cs | 2 +- .../Modules/Common/Modules.Common.Core/Paging/Filter.cs | 2 +- .../Modules/Common/Modules.Common.Core/Paging/FilterLogic.cs | 2 +- .../Common/Modules.Common.Core/Paging/FilterOperator.cs | 2 +- .../Modules/Common/Modules.Common.Core/Paging/IPageRequest.cs | 2 +- .../Modules/Common/Modules.Common.Core/Paging/IPagedList.cs | 2 +- .../Modules/Common/Modules.Common.Core/Paging/PagedList.cs | 2 +- .../Common/Modules.Common.Core/Paging/PaginationFilter.cs | 2 +- .../Modules.Common.Core/Paging/PaginationFilterExtensions.cs | 2 +- .../Modules/Common/Modules.Common.Core/Paging/Search.cs | 2 +- .../Common/Modules.Common.Core/Persistence/DatabaseOptions.cs | 2 +- .../Persistence/IConnectionStringValidator.cs | 2 +- .../Common/Modules.Common.Core/Persistence/IDbInitializer.cs | 2 +- .../Common/Modules.Common.Core/Persistence/IRepository.cs | 2 +- .../Specifications/EntitiesByBaseFilterSpec.cs | 2 +- .../Specifications/EntitiesByPaginationFilterSpec.cs | 2 +- .../Modules/Common/Modules.Common.Core/Storage/FileType.cs | 2 +- .../Common/Modules.Common.Core/Storage/FileUploadRequest.cs | 2 +- .../Common/Modules.Common.Core/Storage/IStorageService.cs | 2 +- .../Caching/DistributedCacheService.cs | 2 +- .../Modules.Common.Infrastructure/Caching/Extensions.cs | 3 ++- .../Common/Extensions/EnumExtensions.cs | 2 +- .../Common/Extensions/RegexExtensions.cs | 2 +- .../Constants/QueryStringKeys.cs | 2 +- .../Common/Modules.Common.Infrastructure/Cors/CorsOptions.cs | 2 +- .../Common/Modules.Common.Infrastructure/Cors/Extensions.cs | 2 +- .../Exceptions/CustomExceptionHandler.cs | 2 +- .../Common/Modules.Common.Infrastructure/Extensions.cs | 2 +- .../Extensions/PagedListExtensions.cs | 2 +- .../Extensions/RepositoryExtensions.cs | 2 +- .../Common/Modules.Common.Infrastructure/FshInfrastructure.cs | 2 +- .../HealthChecks/HealthCheckEndpoint.cs | 2 +- .../HealthChecks/HealthCheckMiddleware.cs | 3 +-- .../Common/Modules.Common.Infrastructure/Jobs/Extensions.cs | 2 +- .../Modules.Common.Infrastructure/Jobs/FshJobActivator.cs | 2 +- .../Common/Modules.Common.Infrastructure/Jobs/FshJobFilter.cs | 2 +- .../Jobs/HangfireCustomBasicAuthenticationFilter.cs | 2 +- .../Modules.Common.Infrastructure/Jobs/HangfireOptions.cs | 2 +- .../Modules.Common.Infrastructure/Jobs/HangfireService.cs | 2 +- .../Common/Modules.Common.Infrastructure/Jobs/LogJobFilter.cs | 2 +- .../Logging/Serilog/Extensions.cs | 2 +- .../Logging/Serilog/StaticLogger.cs | 2 +- .../Common/Modules.Common.Infrastructure/Mail/Extensions.cs | 2 +- .../Modules.Common.Infrastructure/Mail/SmtpMailService.cs | 2 +- .../Messaging/CQRS/CommandDispatcher.cs | 2 +- .../Messaging/CQRS/Extensions.cs | 2 +- .../Messaging/CQRS/QueryDispatcher.cs | 2 +- .../Messaging/CQRS/Validation/CommandValidation.cs | 2 +- .../Messaging/CQRS/Validation/QueryValidation.cs | 2 +- .../Messaging/CQRS/Validation/ValidationHelper.cs | 2 +- .../Messaging/Events/Extensions.cs | 2 +- .../Messaging/Events/InMemoryEventPublisher.cs | 2 +- .../Modules.Common.Infrastructure/Modules/Extensions.cs | 2 +- .../Modules.Common.Infrastructure/Modules/IFrameworkModule.cs | 2 +- .../OpenApi/ConfigureSwaggerOptions.cs | 2 +- .../Modules.Common.Infrastructure/OpenApi/Extensions.cs | 2 +- .../OpenApi/SwaggerDefaultValues.cs | 2 +- .../Persistence/AppendGlobalQueryFilterExtension.cs | 2 +- .../Modules.Common.Infrastructure/Persistence/DbProviders.cs | 2 +- .../Modules.Common.Infrastructure/Persistence/Extensions.cs | 2 +- .../Modules.Common.Infrastructure/Persistence/FshDbContext.cs | 2 +- .../Persistence/Services/ConnectionStringValidator.cs | 2 +- .../Modules.Common.Infrastructure/RateLimit/Extensions.cs | 2 +- .../RateLimit/RateLimitOptions.cs | 2 +- .../SecurityHeaders/Extensions.cs | 2 +- .../SecurityHeaders/SecurityHeaderOptions.cs | 2 +- .../SecurityHeaders/SecurityHeaders.cs | 2 +- .../Storage/LocalStorageService.cs | 3 +-- .../Storage/StorageServiceRegistration.cs | 2 +- .../Modules.Common.Shared/Authorization/CustomClaims.cs | 2 +- .../Modules.Common.Shared/Authorization/EndpointExtensions.cs | 2 +- .../Authorization/RequiredPermissionAttribute.cs | 2 +- .../Constants/AuthenticationConstants.cs | 2 +- .../Common/Modules.Common.Shared/Constants/FshActions.cs | 2 +- .../Common/Modules.Common.Shared/Constants/FshClaims.cs | 2 +- .../Common/Modules.Common.Shared/Constants/FshPermissions.cs | 4 +--- .../Common/Modules.Common.Shared/Constants/FshResources.cs | 2 +- .../Common/Modules.Common.Shared/Constants/FshRoles.cs | 2 +- .../Common/Modules.Common.Shared/Constants/TenantConstants.cs | 2 +- .../Extensions/ClaimsPrincipalExtensions.cs | 2 +- .../Modules.Common.Shared/Extensions/HttpContextExtensions.cs | 2 +- .../Modules.Common.Shared/Multitenancy/FshTenantInfo.cs | 2 +- .../Modules.Common.Shared/Multitenancy/IFshTenantInfo.cs | 2 +- .../Multitenancy/MultiTenancyConstants.cs | 2 +- .../Identity/Modules.Identity.Contracts/Dtos/RoleDto.cs | 2 +- .../Identity/Modules.Identity.Contracts/Dtos/TokenDto.cs | 2 +- .../Identity/Modules.Identity.Contracts/Dtos/UserDto.cs | 2 +- .../Identity/Modules.Identity.Contracts/Dtos/UserRoleDto.cs | 2 +- .../Modules.Identity.Contracts/IdentityModuleConstants.cs | 2 +- .../v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs | 2 +- .../v1/Roles/UpsertRole/UpsertRoleCommand.cs | 2 +- .../v1/Tokens/RefreshToken/RefreshTokenCommand.cs | 2 +- .../v1/Tokens/TokenGeneration/TokenGenerationCommand.cs | 2 +- .../v1/Users/AssignUserRoles/AssignUserRolesCommand.cs | 2 +- .../v1/Users/ChangePassword/ChangePasswordCommand.cs | 2 +- .../v1/Users/ForgotPassword/ForgotPasswordCommand.cs | 2 +- .../v1/Users/RegisterUser/RegisterUserCommand.cs | 2 +- .../v1/Users/RegisterUser/RegisterUserResponse.cs | 2 +- .../v1/Users/ResetPassword/ResetPasswordCommand.cs | 2 +- .../v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs | 2 +- .../v1/Users/UpdateUser/UpdateUserCommand.cs | 2 +- .../Modules.Identity/Authorization/CurrentUserMiddleware.cs | 2 +- .../Identity/Modules.Identity/Authorization/Jwt/Extensions.cs | 2 +- .../Authorization/PathAwareAuthorizationHandler.cs | 3 +-- .../Authorization/PermissionAuthorizationRequirement.cs | 2 +- .../RequiredPermissionAuthorizationExtensions.cs | 2 +- .../Authorization/RequiredPermissionAuthorizationHandler.cs | 2 +- .../Identity/Modules.Identity/Data/IdentityConfigurations.cs | 2 +- .../Identity/Modules.Identity/Data/IdentityDbContext.cs | 2 +- .../Identity/Modules.Identity/Data/IdentityDbInitializer.cs | 2 +- .../Modules.Identity/Features/v1/RoleClaims/FshRoleClaim.cs | 2 +- .../Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs | 3 +-- .../Identity/Modules.Identity/Features/v1/Roles/FshRole.cs | 2 +- .../Features/v1/Roles/GetRole/GetRoleEndpoint.cs | 3 +-- .../GetRoleWithPermissions/GetRolePermissionsEndpoint.cs | 2 +- .../Features/v1/Roles/GetRoles/GetRolesEndpoint.cs | 2 +- .../Modules.Identity/Features/v1/Roles/RoleService.cs | 2 +- .../UpdatePermissionsCommandValidator.cs | 2 +- .../UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs | 2 +- .../v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs | 2 +- .../v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs | 2 +- .../v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs | 2 +- .../Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs | 2 +- .../Tokens/TokenGeneration/TokenGenerationCommandHandler.cs | 2 +- .../v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs | 2 +- .../v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs | 2 +- .../v1/Users/ChangePassword/ChangePasswordEndpoint.cs | 2 +- .../v1/Users/ChangePassword/ChangePasswordValidator.cs | 2 +- .../Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs | 2 +- .../Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs | 2 +- .../v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs | 2 +- .../v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs | 2 +- .../Identity/Modules.Identity/Features/v1/Users/FshUser.cs | 2 +- .../Features/v1/Users/GetUser/GetUserEndpoint.cs | 2 +- .../v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs | 2 +- .../v1/Users/GetUserProfile/GetUserProfileEndpoint.cs | 2 +- .../Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs | 2 +- .../Features/v1/Users/GetUsers/GetUsersListEndpoint.cs | 2 +- .../Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs | 2 +- .../v1/Users/ResetPassword/ResetPasswordCommandValidator.cs | 2 +- .../Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs | 2 +- .../v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs | 2 +- .../v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs | 2 +- .../v1/Users/UpdateUser/UpdateUserCommandValidator.cs | 2 +- .../Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs | 2 +- .../Modules.Identity/Features/v1/Users/UserImageValidator.cs | 2 +- .../Modules/Identity/Modules.Identity/IdentityModule.cs | 2 +- .../Modules.Identity/Options/ConfigureJwtBearerOptions.cs | 2 +- .../Modules/Identity/Modules.Identity/Options/JwtOptions.cs | 2 +- .../Identity/Modules.Identity/Services/CurrentUserService.cs | 2 +- .../Identity/Modules.Identity/Services/IRoleService.cs | 3 +-- .../Identity/Modules.Identity/Services/ITokenService.cs | 2 +- .../Identity/Modules.Identity/Services/IUserService.cs | 2 +- .../Identity/Modules.Identity/Services/TokenService.cs | 2 +- .../Modules.Identity/Services/UserService.Password.cs | 2 +- .../Modules.Identity/Services/UserService.Permissions.cs | 2 +- .../Modules/Identity/Modules.Identity/Services/UserService.cs | 2 +- .../Tenant/Modules.Tenant.Contracts/TenantConstants.cs | 2 +- .../v1/ActivateTenant/ActivateTenantCommand.cs | 2 +- .../Modules/Tenant/Modules.Tenant/Data/TenantDbContext.cs | 2 +- src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs | 2 +- .../v1/ActivateTenant/ActivateTenantCommandHandler.cs | 2 +- .../v1/ActivateTenant/ActivateTenantCommandValidator.cs | 2 +- .../Features/v1/ActivateTenant/ActivateTenantEndpoint.cs | 2 +- .../Features/v1/CreateTenant/CreateTenantCommandHandler.cs | 2 +- .../Features/v1/CreateTenant/CreateTenantCommandValidator.cs | 2 +- .../Features/v1/CreateTenant/CreateTenantEndpoint.cs | 2 +- .../Features/v1/DisableTenant/DisableTenantCommandHandler.cs | 2 +- .../v1/DisableTenant/DisableTenantCommandValidator.cs | 2 +- .../Features/v1/DisableTenant/DisableTenantEndpoint.cs | 2 +- .../Features/v1/GetTenantById/GetTenantByIdEndpoint.cs | 2 +- .../Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs | 2 +- .../Features/v1/GetTenants/GetTenantsEndpoint.cs | 2 +- .../Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs | 2 +- .../v1/UpgradeTenant/UpgradeTenantCommandValidator.cs | 2 +- .../Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs | 2 +- .../Modules/Tenant/Modules.Tenant/Services/ITenantService.cs | 2 +- .../Modules/Tenant/Modules.Tenant/Services/TenantService.cs | 2 +- src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs | 2 +- .../PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs | 2 +- .../PostgreSQL/Identity/20250416110641_Add Identity Schema.cs | 2 +- .../PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs | 2 +- 233 files changed, 235 insertions(+), 242 deletions(-) diff --git a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/AuditingConstants.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/AuditingConstants.cs index 88b1ae537..4b21461fc 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/AuditingConstants.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/AuditingConstants.cs @@ -15,4 +15,4 @@ public static class Routes public const string Base = "/v1/auditing"; public const string GetUserLogs = $"{Base}/logs/{{userId:guid}}"; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Dtos/TrailDto.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Dtos/TrailDto.cs index 0ca6e89ae..059826e87 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Dtos/TrailDto.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Dtos/TrailDto.cs @@ -16,4 +16,4 @@ public class TrailDto public Dictionary OldValues { get; set; } = new(); public Dictionary NewValues { get; set; } = new(); public Collection ModifiedProperties { get; set; } = new(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Enums/AuditOperation.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Enums/AuditOperation.cs index de953a2e4..ff20b12d4 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Enums/AuditOperation.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Enums/AuditOperation.cs @@ -5,4 +5,4 @@ public enum AuditOperation Create = 1, Update = 2, Delete = 3 -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs index c535a8684..b42a68b33 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Events/IntegrationEvents/AuditPublishedEvent.cs @@ -11,4 +11,4 @@ public AuditPublishedEvent(IReadOnlyCollection trails) { Trails = trails; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs index 8a318cf19..6a4db07a4 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs @@ -41,4 +41,4 @@ public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuil return endpoints; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingConfiguration.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingConfiguration.cs index bd4ca0495..ac9eb0727 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingConfiguration.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingConfiguration.cs @@ -15,4 +15,4 @@ public void Configure(EntityTypeBuilder builder) builder.HasKey(a => a.Id); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs index 447d9fd50..3ed184bfe 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs @@ -23,4 +23,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.ApplyConfigurationsFromAssembly(typeof(AuditingDbContext).Assembly); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbInitializer.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbInitializer.cs index 66d0ebe23..b248631bb 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbInitializer.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbInitializer.cs @@ -16,4 +16,4 @@ public Task SeedAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Data/IAuditingDbContext.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/IAuditingDbContext.cs index 3d53d252a..28e262da5 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Data/IAuditingDbContext.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Data/IAuditingDbContext.cs @@ -6,4 +6,4 @@ public interface IAuditingDbContext { DbSet Trails { get; } Task SaveChangesAsync(CancellationToken cancellationToken); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs index ee130b6ed..fa58e95f4 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs @@ -137,4 +137,4 @@ public static bool HasChangedOwnedEntities(this EntityEntry entry) => r.TargetEntry != null && r.TargetEntry.Metadata.IsOwned() && (r.TargetEntry.State == EntityState.Added || r.TargetEntry.State == EntityState.Modified)); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs b/src/framework/Modules/Auditing/Modules.Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs index aaca2ed67..877d22b40 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/EventHandlers/AuditPublishedIntegrationEventHandler.cs @@ -38,4 +38,4 @@ public async Task HandleAsync(AuditPublishedEvent notification, CancellationToke logger.LogError(ex, "Unexpected error while saving audit trails."); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Features/Entities/Trail.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/Entities/Trail.cs index 14195b970..2ced3612c 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Features/Entities/Trail.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Features/Entities/Trail.cs @@ -66,4 +66,4 @@ public void AddModifiedProperty(string property) private static string Serialize(object obj) => JsonSerializer.Serialize(obj); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs index d24ffb998..7603ebaff 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsEndpoint.cs @@ -25,4 +25,4 @@ public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) .WithDescription("Returns the audit trail details for a specific user.") .RequirePermission("Permissions.AuditTrails.View"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Mappings/TrailMappings.cs b/src/framework/Modules/Auditing/Modules.Auditing/Mappings/TrailMappings.cs index 8fd638387..a50325f53 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Mappings/TrailMappings.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Mappings/TrailMappings.cs @@ -53,4 +53,4 @@ public static IReadOnlyList ToEntityList(this IEnumerable dtos) { return dtos.Select(dto => dto.ToEntity()).ToList(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Services/AuditService.cs b/src/framework/Modules/Auditing/Modules.Auditing/Services/AuditService.cs index 510d2b501..82344479e 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Services/AuditService.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Services/AuditService.cs @@ -16,4 +16,4 @@ public async Task> GetUserTrailsAsync(Guid userId) return trails.ToDtoList(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Services/IAuditService.cs b/src/framework/Modules/Auditing/Modules.Auditing/Services/IAuditService.cs index 40cf3608c..1ac37e58b 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Services/IAuditService.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Services/IAuditService.cs @@ -4,4 +4,4 @@ namespace FSH.Framework.Auditing.Services; public interface IAuditService { Task> GetUserTrailsAsync(Guid userId); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheOptions.cs index b861c2e06..ae06641a3 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheOptions.cs @@ -1,6 +1,6 @@ -namespace FSH.Framework.Core.Caching; +namespace FSH.Modules.Common.Core.Caching; public class CacheOptions { public string Redis { get; set; } = string.Empty; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs index 5f786e710..a5b0448dd 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs @@ -39,4 +39,4 @@ public static class CacheServiceExtensions return value; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs index 6639a0215..7a486006d 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs @@ -15,4 +15,4 @@ public class AuditableEntity : BaseEntity, IAuditable, ISoftDeletable public abstract class AuditableEntity : AuditableEntity { protected AuditableEntity() => Id = Guid.NewGuid(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs index 953fbd2e5..24ba12ec1 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs @@ -20,4 +20,4 @@ public void QueueDomainEvent(AppEvent @event) public abstract class BaseEntity : BaseEntity { protected BaseEntity() => Id = Guid.NewGuid(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs index cc98c00db..7c54235fd 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs @@ -4,4 +4,4 @@ // Repositories will only work with aggregate roots, not their children public interface IAggregateRoot : IEntity { -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs index edfa8ab9f..99aa2972e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs @@ -6,4 +6,4 @@ public interface IAuditable Guid CreatedBy { get; } DateTimeOffset LastModified { get; } Guid? LastModifiedBy { get; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs index 497568f6c..2c050eda2 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs @@ -11,4 +11,4 @@ public interface IEntity public interface IEntity : IEntity { TId Id { get; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs index d129d02e4..21ff3bdfb 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs @@ -4,4 +4,4 @@ public interface ISoftDeletable { DateTimeOffset? Deleted { get; set; } Guid? DeletedBy { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs index cf3688fb4..b8670e8b1 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs @@ -38,4 +38,4 @@ public CustomException( ErrorMessages = errors?.ToList() ?? new List(); StatusCode = statusCode; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs index 1041b72a3..7b49705f6 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs @@ -21,4 +21,4 @@ public ForbiddenException(string message, IEnumerable errors) : base(message, errors.ToList(), HttpStatusCode.Forbidden) { } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs index 0d12f8dbf..0f322d033 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs @@ -16,4 +16,4 @@ public NotFoundException(string message, IEnumerable errors) : base(message, errors.ToList(), HttpStatusCode.NotFound) { } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs index 35802df53..b807f9886 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs @@ -21,4 +21,4 @@ public UnauthorizedException(string message, IEnumerable errors) : base(message, errors.ToList(), HttpStatusCode.Unauthorized) { } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUser.cs b/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUser.cs index 2e8d6b91a..363df8f40 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUser.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUser.cs @@ -16,4 +16,4 @@ public interface ICurrentUser bool IsInRole(string role); IEnumerable? GetUserClaims(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUserInitializer.cs b/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUserInitializer.cs index 4773338fe..93bf622e6 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUserInitializer.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/ExecutionContext/ICurrentUserInitializer.cs @@ -6,4 +6,4 @@ public interface ICurrentUserInitializer void SetCurrentUser(ClaimsPrincipal user); void SetCurrentUserId(string userId); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/FshCore.cs b/src/framework/Modules/Common/Modules.Common.Core/FshCore.cs index 1891dc8d2..df778e0a8 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/FshCore.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/FshCore.cs @@ -2,4 +2,4 @@ public static class FshCore { public static string Name { get; set; } = "FshCore"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Helpers/JsonHelpers.cs b/src/framework/Modules/Common/Modules.Common.Core/Helpers/JsonHelpers.cs index 0ef4c7c47..4b99f4a6c 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Helpers/JsonHelpers.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Helpers/JsonHelpers.cs @@ -10,4 +10,4 @@ public static class JsonHelpers WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Jobs/IJobService.cs b/src/framework/Modules/Common/Modules.Common.Core/Jobs/IJobService.cs index 7016ae79d..b7b7d15f0 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Jobs/IJobService.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Jobs/IJobService.cs @@ -37,4 +37,4 @@ public interface IJobService string Schedule(Expression> methodCall, DateTimeOffset enqueueAt); string Schedule(Expression> methodCall, DateTimeOffset enqueueAt); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Mail/IMailService.cs b/src/framework/Modules/Common/Modules.Common.Core/Mail/IMailService.cs index c5e000951..f8ddc44c8 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Mail/IMailService.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Mail/IMailService.cs @@ -2,4 +2,4 @@ public interface IMailService { Task SendAsync(MailRequest request, CancellationToken ct); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Mail/MailOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Mail/MailOptions.cs index 4b0116957..84bd4e9f3 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Mail/MailOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Mail/MailOptions.cs @@ -12,4 +12,4 @@ public class MailOptions public string? Password { get; set; } public string? DisplayName { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Mail/MailRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Mail/MailRequest.cs index 662dcd401..e01723e63 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Mail/MailRequest.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Mail/MailRequest.cs @@ -24,4 +24,4 @@ public class MailRequest(Collection to, string subject, string? body = n public IDictionary AttachmentData { get; } = attachmentData ?? new Dictionary(); public IDictionary Headers { get; } = headers ?? new Dictionary(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs index d6acb6af8..11935bb26 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs @@ -1,4 +1,4 @@ namespace FSH.Framework.Core.Messaging.CQRS; // Marker for command requests (intended to modify system state) -public interface ICommand : IRequest { } +public interface ICommand : IRequest { } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs index ebc5e4200..6edcac07b 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs @@ -5,4 +5,4 @@ public interface ICommandDispatcher /// Sends a command to its handler. /// Task SendAsync(ICommand command, CancellationToken ct = default); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs index 525b0319b..90f23ef67 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs @@ -9,4 +9,4 @@ public interface ICommandHandler where TCommand : ICommand { Task HandleAsync(TCommand command, CancellationToken cancellationToken = default); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs index 254880121..6f8e4a66e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs @@ -1,4 +1,4 @@ namespace FSH.Framework.Core.Messaging.CQRS; // Marker for query requests (intended to return data without modifying state) -public interface IQuery : IRequest { } +public interface IQuery : IRequest { } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryDispatcher.cs index ed0096d2f..1e10aedb0 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryDispatcher.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryDispatcher.cs @@ -2,4 +2,4 @@ public interface IQueryDispatcher { Task SendAsync(IQuery query, CancellationToken ct = default); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryHandler.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryHandler.cs index ba5f5c6d8..f3ecce9e6 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryHandler.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQueryHandler.cs @@ -9,4 +9,4 @@ public interface IQueryHandler where TQuery : IQuery { Task HandleAsync(TQuery query, CancellationToken cancellationToken = default); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs index 0ddf2c223..9e773539e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs @@ -1,4 +1,4 @@ namespace FSH.Framework.Core.Messaging.CQRS; // Represents a generic request with a response -public interface IRequest { } +public interface IRequest { } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/AppEvent.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/AppEvent.cs index e59532448..c25be7212 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/AppEvent.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/AppEvent.cs @@ -2,4 +2,4 @@ public abstract record AppEvent : IEvent { public DateTime RaisedOn { get; protected set; } = DateTime.UtcNow; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEvent.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEvent.cs index 03a34c203..1f929ce24 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEvent.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEvent.cs @@ -1,4 +1,4 @@ namespace FSH.Framework.Core.Messaging.Events; public interface IEvent { -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventHandler.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventHandler.cs index e01700899..01c2bbe2d 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventHandler.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventHandler.cs @@ -2,4 +2,4 @@ public interface IEventHandler where TEvent : IEvent { Task HandleAsync(TEvent appEvent, CancellationToken cancellationToken = default); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventPublisher.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventPublisher.cs index a395995e6..a50515af8 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventPublisher.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/IEventPublisher.cs @@ -2,4 +2,4 @@ public interface IEventPublisher { Task PublishAsync(IEvent appEvent, CancellationToken cancellationToken = default); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/INotification.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/INotification.cs index c7b8f27dc..eece5f53e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/INotification.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/INotification.cs @@ -1,4 +1,4 @@ namespace FSH.Framework.Core.Messaging.Events; public interface INotification { -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/Notification.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/Notification.cs index 8ed5c121b..88948d147 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/Notification.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/Events/Notification.cs @@ -2,4 +2,4 @@ public abstract record Notification : INotification { public DateTime RaisedOn { get; protected set; } = DateTime.UtcNow; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs b/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs index 9b693915e..3e284de1e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs @@ -6,4 +6,4 @@ namespace FSH.Framework.Core.Modules; public interface ICoreModule { IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs index 97e1c3542..12e0de52c 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs @@ -3,4 +3,4 @@ public class OriginOptions { public Uri? OriginUrl { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/BaseFilter.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/BaseFilter.cs index 2bb5b099b..3a80bbf19 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/BaseFilter.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/BaseFilter.cs @@ -16,4 +16,4 @@ public class BaseFilter /// Advanced column filtering with logical operators and query operators is supported. /// public Filter? AdvancedFilter { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/Filter.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/Filter.cs index 6407996e6..a447e6dfc 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/Filter.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/Filter.cs @@ -14,4 +14,4 @@ public class Filter public FilterOperator? Operator { get; set; } public object? Value { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterLogic.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterLogic.cs index 51767a14b..3009824c0 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterLogic.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterLogic.cs @@ -5,4 +5,4 @@ public enum FilterLogic And, Or, Xor -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterOperator.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterOperator.cs index 0887f7e1f..905af3b77 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterOperator.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/FilterOperator.cs @@ -11,4 +11,4 @@ public enum FilterOperator StartsWith, EndsWith, Contains -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/IPageRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/IPageRequest.cs index 41ea56635..aaed1b2d9 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/IPageRequest.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/IPageRequest.cs @@ -16,4 +16,4 @@ public interface IPageRequest /// Optional sort order (e.g., "name asc", "created desc"). string? SortOrder { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/IPagedList.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/IPagedList.cs index c55b50726..316ac4c6e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/IPagedList.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/IPagedList.cs @@ -9,4 +9,4 @@ public interface IPagedList int TotalPages { get; } bool HasPrevious { get; } bool HasNext { get; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/PagedList.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/PagedList.cs index 083664489..639a9167e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/PagedList.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/PagedList.cs @@ -19,4 +19,4 @@ int TotalCount public PagedList MapTo(Func mapper) where TR : class => new(Items.Select(mapper).ToList(), PageNumber, PageSize, TotalCount); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilter.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilter.cs index 19b131d02..d0532bf19 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilter.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilter.cs @@ -8,4 +8,4 @@ public class PaginationFilter : BaseFilter, IPageRequest public string? Filters { get; set; } public string? SortOrder { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilterExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilterExtensions.cs index 41891100d..8819b005f 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilterExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/PaginationFilterExtensions.cs @@ -7,4 +7,4 @@ public static class PaginationFilterExtensions /// public static bool HasOrderBy(this PaginationFilter? filter) => filter?.OrderBy?.Any() == true; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Paging/Search.cs b/src/framework/Modules/Common/Modules.Common.Core/Paging/Search.cs index ec78cb343..0cb1a264f 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Paging/Search.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Paging/Search.cs @@ -20,4 +20,4 @@ public class Search /// public bool IsValid => Fields?.Count > 0 && !string.IsNullOrWhiteSpace(Keyword); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs index 5be4fb9e0..d5590f6e5 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs @@ -13,4 +13,4 @@ public IEnumerable Validate(ValidationContext validationContex yield return new ValidationResult("connection string cannot be empty.", new[] { nameof(ConnectionString) }); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IConnectionStringValidator.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IConnectionStringValidator.cs index 413e4fc76..69681ac5f 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IConnectionStringValidator.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IConnectionStringValidator.cs @@ -2,4 +2,4 @@ public interface IConnectionStringValidator { bool TryValidate(string connectionString, string? dbProvider = null); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IDbInitializer.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IDbInitializer.cs index ed4a08c84..509895698 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IDbInitializer.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IDbInitializer.cs @@ -3,4 +3,4 @@ public interface IDbInitializer { Task MigrateAsync(CancellationToken cancellationToken); Task SeedAsync(CancellationToken cancellationToken); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs index 3915bb3ca..a1b59c851 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs @@ -10,4 +10,4 @@ public interface IRepository : IRepositoryBase public interface IReadRepository : IReadRepositoryBase where T : class, IAggregateRoot { -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByBaseFilterSpec.cs b/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByBaseFilterSpec.cs index 4b14bd2bf..0ee0231b2 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByBaseFilterSpec.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByBaseFilterSpec.cs @@ -13,4 +13,4 @@ public class EntitiesByBaseFilterSpec : Specification where T : class { public EntitiesByBaseFilterSpec(BaseFilter filter) => Query.SearchBy(filter); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByPaginationFilterSpec.cs b/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByPaginationFilterSpec.cs index a2ff6ba52..bdbb61091 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByPaginationFilterSpec.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Specifications/EntitiesByPaginationFilterSpec.cs @@ -14,4 +14,4 @@ public class EntitiesByPaginationFilterSpec : EntitiesByBaseFilterSpec whe public EntitiesByPaginationFilterSpec(PaginationFilter filter) : base(filter) => Query.PaginateBy(filter); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Storage/FileType.cs b/src/framework/Modules/Common/Modules.Common.Core/Storage/FileType.cs index 6abc1305b..31d82817d 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Storage/FileType.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Storage/FileType.cs @@ -21,4 +21,4 @@ public static FileValidationRules GetRules(FileType type) => FileType.Pdf => new() { AllowedExtensions = [".pdf"], MaxSizeInMB = 10 }, _ => throw new NotSupportedException($"Unsupported file type: {type}") }; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Storage/FileUploadRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Storage/FileUploadRequest.cs index 086b3bd70..6b7d52901 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Storage/FileUploadRequest.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Storage/FileUploadRequest.cs @@ -4,4 +4,4 @@ public class FileUploadRequest public string FileName { get; init; } = default!; public string ContentType { get; init; } = default!; public IReadOnlyList Data { get; init; } = Array.Empty(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Storage/IStorageService.cs b/src/framework/Modules/Common/Modules.Common.Core/Storage/IStorageService.cs index b4635fdaa..ce166d4c4 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Storage/IStorageService.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Storage/IStorageService.cs @@ -7,4 +7,4 @@ Task UploadAsync( CancellationToken cancellationToken = default) where T : class; Task RemoveAsync(string path, CancellationToken cancellationToken = default); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs index 4a42e71ae..6da97a038 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs @@ -158,4 +158,4 @@ private static DistributedCacheEntryOptions GetOptions(TimeSpan? slidingExpirati options.SetAbsoluteExpiration(TimeSpan.FromMinutes(15)); return options; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs index c389a52a1..35be5ef2f 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs @@ -1,4 +1,5 @@ using FSH.Framework.Core.Caching; +using FSH.Modules.Common.Core.Caching; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Serilog; @@ -31,4 +32,4 @@ internal static IServiceCollection ConfigureCaching(this IServiceCollection serv return services; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs index d1f3014aa..b84b4ba12 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs @@ -24,4 +24,4 @@ public static ReadOnlyCollection GetDescriptionList(this Enum enumValue) string result = enumValue.GetDescription(); return new ReadOnlyCollection(result.Split(',').ToList()); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/RegexExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/RegexExtensions.cs index 0204acd3c..a78ba1fb0 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/RegexExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/RegexExtensions.cs @@ -9,4 +9,4 @@ public static string ReplaceWhitespace(this string input, string replacement) { return Whitespace.Replace(input, replacement); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Constants/QueryStringKeys.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Constants/QueryStringKeys.cs index 0ea2d3050..d2c81eb56 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Constants/QueryStringKeys.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Constants/QueryStringKeys.cs @@ -3,4 +3,4 @@ public static class QueryStringKeys { public const string Code = "code"; public const string UserId = "userId"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/CorsOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/CorsOptions.cs index 289b9e3d3..4491c1c49 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/CorsOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/CorsOptions.cs @@ -8,4 +8,4 @@ public CorsOptions() } public Collection AllowedOrigins { get; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/Extensions.cs index d559de206..0f5e84701 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Cors/Extensions.cs @@ -22,4 +22,4 @@ internal static IApplicationBuilder UseCorsPolicy(this IApplicationBuilder app) { return app.UseCors(CorsPolicy); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs index e4c5ed7ef..f2f7b0ded 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs @@ -48,4 +48,4 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken).ConfigureAwait(false); return true; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs index 515529b0b..576db57f3 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs @@ -89,4 +89,4 @@ public static WebApplication UseFshFramework(this WebApplication app) app.UseAuthorization(); return app; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/PagedListExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/PagedListExtensions.cs index bad0b79d1..c7e04ebe9 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/PagedListExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/PagedListExtensions.cs @@ -9,4 +9,4 @@ public static PagedList AdaptPagedList(this PagedList paged) where T : class where TR : class => new(paged.Items.Adapt>(), paged.PageNumber, paged.PageSize, paged.TotalCount); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/RepositoryExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/RepositoryExtensions.cs index 3596667a5..540a29280 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/RepositoryExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions/RepositoryExtensions.cs @@ -19,4 +19,4 @@ public static async Task> PaginatedListAsync(items, filter.PageNumber, filter.PageSize, totalCount); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/FshInfrastructure.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/FshInfrastructure.cs index d6b702c58..f30f239db 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/FshInfrastructure.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/FshInfrastructure.cs @@ -2,4 +2,4 @@ public class FshInfrastructure { public static string Name { get; set; } = "FshInfrastructure"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckEndpoint.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckEndpoint.cs index af26e38d5..cba3ee344 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckEndpoint.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckEndpoint.cs @@ -36,4 +36,4 @@ internal static RouteHandlerBuilder MapCustomHealthCheckEndpoint(this IEndpointR .WithDescription("Provides detailed health information about the application.") .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckMiddleware.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckMiddleware.cs index 7f7666973..e89469873 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckMiddleware.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/HealthChecks/HealthCheckMiddleware.cs @@ -32,5 +32,4 @@ public async Task InvokeAsync(HttpContext context) context.Response.ContentType = "application/json"; await context.Response.WriteAsync(JsonSerializer.Serialize(response)); } -} - +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs index 2388ac729..c0d758747 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs @@ -68,4 +68,4 @@ internal static IApplicationBuilder UseJobDashboard(this IApplicationBuilder app return app.UseHangfireDashboard(hangfireOptions.Route, dashboardOptions); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobActivator.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobActivator.cs index 516c2faf3..8400b54a8 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobActivator.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobActivator.cs @@ -60,4 +60,4 @@ public override object Resolve(Type type) => ? _context : _scope.ServiceProvider.GetService(serviceType); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobFilter.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobFilter.cs index bdf20459f..a9e40d5fa 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobFilter.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/FshJobFilter.cs @@ -39,4 +39,4 @@ public void OnCreated(CreatedContext context) => Logger.InfoFormat( "Job created with parameters {0}", context.Parameters.Select(x => x.Key + "=" + x.Value).Aggregate((s1, s2) => s1 + ";" + s2)); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs index 731b1b82f..0980dee57 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireCustomBasicAuthenticationFilter.cs @@ -118,4 +118,4 @@ private bool ContainsTwoTokens() { return _tokens.Length == 2; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireOptions.cs index 45f5ac0c6..e5b128303 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireOptions.cs @@ -4,4 +4,4 @@ public class HangfireOptions public string UserName { get; set; } = "admin"; public string Password { get; set; } = "Secure1234!Me"; public string Route { get; set; } = "/jobs"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireService.cs index 027aea85b..62454d869 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireService.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/HangfireService.cs @@ -56,4 +56,4 @@ public string Schedule(Expression> methodCall, DateTimeOffset enque public string Schedule(Expression> methodCall, DateTimeOffset enqueueAt) => BackgroundJob.Schedule(methodCall, enqueueAt); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/LogJobFilter.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/LogJobFilter.cs index 24f1c734e..f495493ca 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/LogJobFilter.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/LogJobFilter.cs @@ -48,4 +48,4 @@ public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction tr "Job {0} state {1} was unapplied.", context.BackgroundJob.Id, context.OldStateName); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs index d02fee79c..96ddbbcbb 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs @@ -55,4 +55,4 @@ public static WebApplicationBuilder ConfigureSerilog(this WebApplicationBuilder }); return builder; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/StaticLogger.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/StaticLogger.cs index 1809893b5..98ec0ac90 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/StaticLogger.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/StaticLogger.cs @@ -16,4 +16,4 @@ public static void EnsureInitialized() .CreateLogger(); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs index 4c772f773..7ce9c9131 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs @@ -10,4 +10,4 @@ internal static IServiceCollection ConfigureMailing(this IServiceCollection serv services.AddOptions().BindConfiguration(nameof(MailOptions)); return services; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/SmtpMailService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/SmtpMailService.cs index 80b90a40c..4216eff2c 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/SmtpMailService.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/SmtpMailService.cs @@ -85,4 +85,4 @@ public async Task SendAsync(MailRequest request, CancellationToken ct) await client.DisconnectAsync(true, ct); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs index 3c86705c8..84b07a38e 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs @@ -18,4 +18,4 @@ public Task SendAsync(ICommand command, Cancell // dynamic dispatch to call HandleAsync(command, ct) return handler.HandleAsync((dynamic)command, ct); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs index c53b04b72..631cc98a5 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs @@ -38,4 +38,4 @@ public static IServiceCollection RegisterCommandAndQueryHandlers(this IServiceCo return services; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/QueryDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/QueryDispatcher.cs index 68c3606f2..37ec66fdb 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/QueryDispatcher.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/QueryDispatcher.cs @@ -18,4 +18,4 @@ public Task SendAsync(IQuery query, Cancellatio return handler.HandleAsync((dynamic)query, ct); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs index 50ed57552..7fb904d36 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs @@ -17,4 +17,4 @@ public async Task SendAsync(ICommand command, C await ValidationHelper.ValidateAsync(command, _serviceProvider, ct); return await _inner.SendAsync(command, ct); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs index 814f3b143..1d2391a33 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs @@ -17,4 +17,4 @@ public async Task SendAsync(IQuery query, Cance await ValidationHelper.ValidateAsync(query, _serviceProvider, ct); return await _inner.SendAsync(query, ct); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs index 49a9c0a58..568aa5aff 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/ValidationHelper.cs @@ -33,4 +33,4 @@ public static async Task ValidateAsync(T request, IServiceProvider provider, if (failures.Count > 0) throw new ValidationException(failures); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs index d35996dbd..ffdcdd818 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs @@ -17,4 +17,4 @@ public static IServiceCollection RegisterInMemoryEventBus(this IServiceCollectio return services; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/InMemoryEventPublisher.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/InMemoryEventPublisher.cs index 5cdb4cdaa..4afd4f6b2 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/InMemoryEventPublisher.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/InMemoryEventPublisher.cs @@ -54,4 +54,4 @@ public async Task PublishAsync(IEvent appEvent, CancellationToken cancellationTo } } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs index d51d2d60b..109287164 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs @@ -39,4 +39,4 @@ public static IApplicationBuilder MapFrameworkModuleEndpoints(this IApplicationB return app; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs index 8e703df31..e69a7db0d 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs @@ -1,4 +1,4 @@ namespace FSH.Framework.Infrastructure.Modules; public interface IFrameworkModule : IModule { -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/ConfigureSwaggerOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/ConfigureSwaggerOptions.cs index 34fda3eeb..8044ddad0 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/ConfigureSwaggerOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/ConfigureSwaggerOptions.cs @@ -46,4 +46,4 @@ private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription descrip return info; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs index b25553001..485148a42 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs @@ -76,4 +76,4 @@ public static WebApplication UseOpenApi(this WebApplication app) } return app; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/SwaggerDefaultValues.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/SwaggerDefaultValues.cs index 73c863c36..9ddca1530 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/SwaggerDefaultValues.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/SwaggerDefaultValues.cs @@ -59,4 +59,4 @@ description.DefaultValue is not DBNull && parameter.Required |= description.IsRequired; } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs index 2186473b7..f5323a2b8 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/AppendGlobalQueryFilterExtension.cs @@ -33,4 +33,4 @@ public static ModelBuilder AppendGlobalQueryFilter(this ModelBuilder return modelBuilder; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/DbProviders.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/DbProviders.cs index f330df512..26d0e063e 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/DbProviders.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/DbProviders.cs @@ -3,4 +3,4 @@ internal static class DbProviders { public const string PostgreSQL = "POSTGRESQL"; public const string MSSQL = "MSSQL"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs index ec4e9661a..653ec9f8c 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs @@ -60,4 +60,4 @@ public static IServiceCollection BindDbContext(this IServiceCollection }); return services; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs index ed22cd663..896428f74 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs @@ -59,4 +59,4 @@ private async Task PublishDomainEventsAsync(CancellationToken cancellationToken await _publisher.PublishAsync(domainEvent, cancellationToken).ConfigureAwait(false); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Services/ConnectionStringValidator.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Services/ConnectionStringValidator.cs index f12b3aba2..b5e27eff8 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Services/ConnectionStringValidator.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Services/ConnectionStringValidator.cs @@ -41,4 +41,4 @@ public bool TryValidate(string connectionString, string? dbProvider = null) return false; } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs index b0960d29f..c18ea3e02 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs @@ -60,4 +60,4 @@ private static string BuildRateLimitResponseMessage(OnRejectedContext onRejected return $"You have reached the maximum number of requests allowed for the address ({hostName})."; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/RateLimitOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/RateLimitOptions.cs index 6fd364c5d..ed1eb39bb 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/RateLimitOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/RateLimitOptions.cs @@ -6,4 +6,4 @@ public class RateLimitOptions public int PermitLimit { get; init; } public int WindowInSeconds { get; init; } public int RejectionStatusCode { get; init; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs index 7d8ea168c..17d4cf71e 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs @@ -66,4 +66,4 @@ internal static IApplicationBuilder UseSecurityHeaders(this IApplicationBuilder return app; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs index 4fac61a59..d867242d3 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaderOptions.cs @@ -4,4 +4,4 @@ public class SecurityHeaderOptions { public bool Enable { get; set; } public SecurityHeaders Headers { get; set; } = default!; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaders.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaders.cs index 596d99a17..24528a945 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaders.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/SecurityHeaders.cs @@ -9,4 +9,4 @@ public class SecurityHeaders public string? ContentSecurityPolicy { get; set; } public string? PermissionsPolicy { get; set; } public string? StrictTransportSecurity { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/LocalStorageService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/LocalStorageService.cs index 7b710874e..03520df83 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/LocalStorageService.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/LocalStorageService.cs @@ -55,5 +55,4 @@ private static string SanitizeFileName(string fileName) { return Regex.Replace(fileName, @"[^a-zA-Z0-9_\.-]", "_"); } -} - +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs index f7ba3b03b..3c4a5689b 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs @@ -10,4 +10,4 @@ public static IServiceCollection ConfigureLocalFileStorage(this IServiceCollecti services.AddScoped(); return services; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Authorization/CustomClaims.cs b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/CustomClaims.cs index 4f1566ca1..2b3bee67f 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Authorization/CustomClaims.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/CustomClaims.cs @@ -7,4 +7,4 @@ public static class CustomClaims public const string ImageUrl = "image_url"; public const string IpAddress = "ipAddress"; public const string Expiration = "exp"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Authorization/EndpointExtensions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/EndpointExtensions.cs index c3b2af3ca..4e7dc2679 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Authorization/EndpointExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/EndpointExtensions.cs @@ -9,4 +9,4 @@ public static TBuilder RequirePermission( { return endpointConventionBuilder.WithMetadata(new RequiredPermissionAttribute(requiredPermission, additionalRequiredPermissions)); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Authorization/RequiredPermissionAttribute.cs b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/RequiredPermissionAttribute.cs index 1730f9959..4995537fa 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Authorization/RequiredPermissionAttribute.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Authorization/RequiredPermissionAttribute.cs @@ -11,4 +11,4 @@ public sealed class RequiredPermissionAttribute(string? requiredPermission, para public HashSet RequiredPermissions { get; } = [requiredPermission!, .. additionalRequiredPermissions]; public string? RequiredPermission { get; } public string[]? AdditionalRequiredPermissions { get; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/AuthenticationConstants.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/AuthenticationConstants.cs index 3bb1edadc..5c20f7604 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/AuthenticationConstants.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/AuthenticationConstants.cs @@ -2,4 +2,4 @@ public static class AuthenticationConstants { public const string AuthenticationScheme = "Bearer"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshActions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshActions.cs index 77d873fae..18a6426e0 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshActions.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshActions.cs @@ -10,4 +10,4 @@ public static class FshActions public const string Generate = nameof(Generate); public const string Clean = nameof(Clean); public const string UpgradeSubscription = nameof(UpgradeSubscription); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshClaims.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshClaims.cs index 11b2eeead..de21ecb25 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshClaims.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshClaims.cs @@ -7,4 +7,4 @@ public static class FshClaims public const string ImageUrl = "image_url"; public const string IpAddress = "ipAddress"; public const string Expiration = "exp"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshPermissions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshPermissions.cs index 6bdd7805b..c00f3d922 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshPermissions.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshPermissions.cs @@ -61,6 +61,4 @@ public static string NameFor(string action, string resource) { return $"Permissions.{resource}.{action}"; } -} - - +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshResources.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshResources.cs index 9e74f2ac6..ac8afa3ac 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshResources.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshResources.cs @@ -9,4 +9,4 @@ public static class FshResources public const string Roles = nameof(Roles); public const string RoleClaims = nameof(RoleClaims); public const string AuditTrails = nameof(AuditTrails); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshRoles.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshRoles.cs index 8b8b6bc1a..c32a857d8 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshRoles.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/FshRoles.cs @@ -20,4 +20,4 @@ public static class FshRoles /// Determines whether the role is a framework-defined default. /// public static bool IsDefault(string roleName) => DefaultRoles.Contains(roleName); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs index 0d1584886..37fbf799b 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs @@ -13,4 +13,4 @@ public static class Root public const string Identifier = "tenant"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Extensions/ClaimsPrincipalExtensions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Extensions/ClaimsPrincipalExtensions.cs index 7baf98a8d..27344cbbb 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Extensions/ClaimsPrincipalExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Extensions/ClaimsPrincipalExtensions.cs @@ -52,4 +52,4 @@ public static DateTimeOffset GetExpiration(this ClaimsPrincipal principal) // Helper method to extract claim value private static string? FindFirstValue(this ClaimsPrincipal principal, string claimType) => principal?.FindFirst(claimType)?.Value; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Extensions/HttpContextExtensions.cs b/src/framework/Modules/Common/Modules.Common.Shared/Extensions/HttpContextExtensions.cs index 50d9538fd..783827c01 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Extensions/HttpContextExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Extensions/HttpContextExtensions.cs @@ -17,4 +17,4 @@ public static string GetIpAddress(this HttpContext context) } return ip; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs index d4cb1c14f..743fffbcf 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs @@ -63,4 +63,4 @@ public void Deactivate() string? ITenantInfo.Identifier { get => Identifier; set => Identifier = value ?? throw new InvalidOperationException("Identifier can't be null."); } string? ITenantInfo.Name { get => Name; set => Name = value ?? throw new InvalidOperationException("Name can't be null."); } string? IFshTenantInfo.ConnectionString { get => ConnectionString; set => ConnectionString = value ?? throw new InvalidOperationException("ConnectionString can't be null."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/IFshTenantInfo.cs b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/IFshTenantInfo.cs index 2f8becc0c..2242ae435 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/IFshTenantInfo.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/IFshTenantInfo.cs @@ -2,4 +2,4 @@ public interface IFshTenantInfo { string? ConnectionString { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/MultiTenancyConstants.cs b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/MultiTenancyConstants.cs index 15dd06b89..f130aa050 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/MultiTenancyConstants.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/MultiTenancyConstants.cs @@ -12,4 +12,4 @@ public static class Root public const string DefaultPassword = "123Pa$$word!"; public const string Identifier = "tenant"; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/RoleDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/RoleDto.cs index d026765e1..e56ad4190 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/RoleDto.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/RoleDto.cs @@ -6,4 +6,4 @@ public class RoleDto public string Name { get; set; } = default!; public string? Description { get; set; } public IReadOnlyCollection? Permissions { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/TokenDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/TokenDto.cs index cc90e9a8f..e66d6eeb5 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/TokenDto.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/TokenDto.cs @@ -1,2 +1,2 @@ namespace FSH.Framework.Identity.Core.Tokens; -public record TokenDto(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); +public record TokenDto(string Token, string RefreshToken, DateTime RefreshTokenExpiryTime); \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserDto.cs index a16d55926..dbf517c36 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserDto.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserDto.cs @@ -18,4 +18,4 @@ public class UserDto public string? PhoneNumber { get; set; } public string? ImageUrl { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserRoleDto.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserRoleDto.cs index dbbb636af..3f045c8b0 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserRoleDto.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/Dtos/UserRoleDto.cs @@ -5,4 +5,4 @@ public class UserRoleDto public string? RoleName { get; set; } public string? Description { get; set; } public bool Enabled { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/IdentityModuleConstants.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/IdentityModuleConstants.cs index 3eec6ae59..836897b29 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/IdentityModuleConstants.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/IdentityModuleConstants.cs @@ -3,4 +3,4 @@ public static class IdentityModuleConstants { public const string SchemaName = "identity"; public const int PasswordLength = 10; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs index 1f04d7daa..54293a342 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpdatePermissions/UpdatePermissionsCommand.cs @@ -11,4 +11,4 @@ public class UpdatePermissionsCommand /// The list of permissions to assign to the role. /// public List Permissions { get; init; } = []; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs index 16ebb4d8a..40ea40878 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Roles/UpsertRole/UpsertRoleCommand.cs @@ -5,4 +5,4 @@ public class UpsertRoleCommand public string Id { get; set; } = default!; public string Name { get; set; } = default!; public string? Description { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs index beb117be8..198dcd441 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs @@ -3,4 +3,4 @@ namespace FSH.Framework.Identity.Core.Tokens; public record RefreshTokenCommand(string Token, string RefreshToken) - : ICommand; + : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs index 168446f3e..276798503 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs @@ -4,4 +4,4 @@ namespace FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; public record TokenGenerationCommand( string Email, string Password) - : ICommand; + : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs index cca339a32..52ab7c2cf 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs @@ -6,4 +6,4 @@ public sealed class AssignUserRolesCommand : ICommand { public required string UserId { get; init; } public List UserRoles { get; init; } = new(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs index c122c85a1..a05711bff 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs @@ -12,4 +12,4 @@ public class ChangePasswordCommand : ICommand /// Confirmation of the new password. public string ConfirmNewPassword { get; init; } = default!; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs index b2cc0e19b..af8254f37 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ForgotPassword/ForgotPasswordCommand.cs @@ -2,4 +2,4 @@ public class ForgotPasswordCommand { public string Email { get; set; } = default!; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs index fe10faa1f..60805f58d 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs @@ -14,4 +14,4 @@ public class RegisterUserCommand : ICommand [JsonIgnore] public string? Origin { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs index dee053912..2631cca8c 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserResponse.cs @@ -1,2 +1,2 @@ namespace FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; -public record RegisterUserResponse(string UserId); +public record RegisterUserResponse(string UserId); \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs index 33c4e3c39..080ecbb76 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ResetPassword/ResetPasswordCommand.cs @@ -6,4 +6,4 @@ public class ResetPasswordCommand public string Password { get; set; } = default!; public string Token { get; set; } = default!; -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs index b049fc54e..89bca2fc7 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ToggleUserStatus/ToggleUserStatusCommand.cs @@ -3,4 +3,4 @@ public class ToggleUserStatusCommand { public bool ActivateUser { get; set; } public string? UserId { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs index 5336e77b4..ad350a117 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/UpdateUser/UpdateUserCommand.cs @@ -10,4 +10,4 @@ public class UpdateUserCommand public string? Email { get; set; } public FileUploadRequest? Image { get; set; } public bool DeleteCurrentImage { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Authorization/CurrentUserMiddleware.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/CurrentUserMiddleware.cs index 09fd012aa..0b92b09fa 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Authorization/CurrentUserMiddleware.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Authorization/CurrentUserMiddleware.cs @@ -11,4 +11,4 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next) _currentUserInitializer.SetCurrentUser(context.User); await next(context); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Authorization/Jwt/Extensions.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/Jwt/Extensions.cs index 4beb33906..1f2c2c058 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Authorization/Jwt/Extensions.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Authorization/Jwt/Extensions.cs @@ -30,4 +30,4 @@ internal static IServiceCollection ConfigureJwtAuth(this IServiceCollection serv }); return services; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs index 7fc3650f8..fe6004743 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Authorization/PathAwareAuthorizationHandler.cs @@ -38,5 +38,4 @@ public async Task HandleAsync( await _fallback.HandleAsync(next, context, policy, authorizeResult); } -} - +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Authorization/PermissionAuthorizationRequirement.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/PermissionAuthorizationRequirement.cs index 8a6e8d6fb..dc425c3ba 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Authorization/PermissionAuthorizationRequirement.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Authorization/PermissionAuthorizationRequirement.cs @@ -1,4 +1,4 @@ using Microsoft.AspNetCore.Authorization; namespace FSH.Framework.Identity.Infrastructure.Authorization; -public class PermissionAuthorizationRequirement : IAuthorizationRequirement; +public class PermissionAuthorizationRequirement : IAuthorizationRequirement; \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs index faaad9f25..05612e9ca 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationExtensions.cs @@ -29,4 +29,4 @@ public static AuthorizationBuilder AddRequiredPermissionPolicy(this Authorizatio return builder; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs index f43aeb098..357a3926b 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Authorization/RequiredPermissionAuthorizationHandler.cs @@ -29,4 +29,4 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context.Succeed(requirement); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityConfigurations.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityConfigurations.cs index 8b256a434..b19a83f34 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityConfigurations.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityConfigurations.cs @@ -70,4 +70,4 @@ public void Configure(EntityTypeBuilder> builder) => builder .ToTable("UserTokens", IdentityModuleConstants.SchemaName) .IsMultiTenant(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs index 85d2e308c..fda0fe7f3 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs @@ -41,4 +41,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder.ConfigureDatabase(_settings.Provider, TenantInfo.ConnectionString); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs index 7a395daee..f287310b6 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs @@ -132,4 +132,4 @@ private async Task SeedAdminUserAsync() await userManager.AddToRoleAsync(adminUser, FshRoles.Admin); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/RoleClaims/FshRoleClaim.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/RoleClaims/FshRoleClaim.cs index 3df953852..dd1ddea47 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/RoleClaims/FshRoleClaim.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/RoleClaims/FshRoleClaim.cs @@ -5,4 +5,4 @@ public class FshRoleClaim : IdentityRoleClaim { public string? CreatedBy { get; init; } public DateTimeOffset CreatedOn { get; init; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs index 7ce3a5cf7..b6b2c1fb7 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/DeleteRole/DeleteRoleEndpoint.cs @@ -19,5 +19,4 @@ public static RouteHandlerBuilder MapDeleteRoleEndpoint(this IEndpointRouteBuild .RequirePermission("Permissions.Roles.Delete") .WithDescription("Remove a role from the system by its ID."); } -} - +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/FshRole.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/FshRole.cs index bc52e556c..850dbc26a 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/FshRole.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/FshRole.cs @@ -11,4 +11,4 @@ public FshRole(string name, string? description = null) Description = description; NormalizedName = name.ToUpperInvariant(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs index a62be69fb..33372598e 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRole/GetRoleEndpoint.cs @@ -19,5 +19,4 @@ public static RouteHandlerBuilder MapGetRoleEndpoint(this IEndpointRouteBuilder .RequirePermission("Permissions.Roles.View") .WithDescription("Retrieve the details of a role by its ID."); } -} - +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs index be97ef606..71566502d 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoleWithPermissions/GetRolePermissionsEndpoint.cs @@ -18,4 +18,4 @@ public static RouteHandlerBuilder MapGetRolePermissionsEndpoint(this IEndpointRo .RequirePermission("Permissions.Roles.View") .WithDescription("get role permissions"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs index 4e5143d43..931ae21e9 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/GetRoles/GetRolesEndpoint.cs @@ -18,4 +18,4 @@ public static RouteHandlerBuilder MapGetRolesEndpoint(this IEndpointRouteBuilder .RequirePermission("Permissions.Roles.View") .WithDescription("Retrieve a list of all roles available in the system."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs index c52d00fa4..6dc84f344 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs @@ -122,4 +122,4 @@ public async Task UpdatePermissionsAsync(string roleId, List per return "permissions updated"; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs index dfff18bf2..d135d5e82 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdatePermissionsCommandValidator.cs @@ -11,4 +11,4 @@ public UpdatePermissionsCommandValidator() RuleFor(r => r.Permissions) .NotNull(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs index cfa631bbf..c1dfe697b 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpdateRolePermissions/UpdateRolePermissionsEndpoint.cs @@ -27,4 +27,4 @@ public static RouteHandlerBuilder MapUpdateRolePermissionsEndpoint(this IEndpoin .RequirePermission("Permissions.Roles.Create") .WithDescription("update role permissions"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs index eb48a66f4..943a6d55d 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/CreateOrUpdateRoleEndpoint.cs @@ -21,4 +21,4 @@ public static RouteHandlerBuilder MapCreateOrUpdateRoleEndpoint(this IEndpointRo .RequirePermission("Permissions.Roles.Create") .WithDescription("Create a new role or update an existing role."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs index 0e1419fd2..ca52ca542 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/UpsertRole/UpsertRoleCommandValidator.cs @@ -8,4 +8,4 @@ public UpsertRoleCommandValidator() { RuleFor(x => x.Name).NotEmpty().WithMessage("Role name is required."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs index de791bcb6..04c2af59d 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs @@ -9,4 +9,4 @@ public RefreshTokenCommandValidator() RuleFor(p => p.Token).Cascade(CascadeMode.Stop).NotEmpty(); RuleFor(p => p.RefreshToken).Cascade(CascadeMode.Stop).NotEmpty(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs index 2b4eeb011..06705cdd5 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenEndpoint.cs @@ -23,4 +23,4 @@ internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpo .WithDescription("refresh JWTs") .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs index 4ca8738c4..133f25b49 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs @@ -16,4 +16,4 @@ public async Task HandleAsync(TokenGenerationCom var token = await tokenService.GenerateTokenAsync(command.Email, command.Password, ip, cancellationToken); return new TokenGenerationCommandResponse(token.Token, token.RefreshToken, token.RefreshTokenExpiryTime); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs index 6202fe896..9524e645b 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationEndpoint.cs @@ -26,4 +26,4 @@ internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) .WithDescription("Generates access and refresh tokens.") .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs index 2fa5c7d58..d3c686aa7 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesEndpoint.cs @@ -22,4 +22,4 @@ internal static RouteHandlerBuilder MapEndpoint(this IEndpointRouteBuilder endpo .WithSummary("assign roles") .WithDescription("assign roles"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs index 61f6cecc6..b02e7dffa 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs @@ -40,4 +40,4 @@ internal static RouteHandlerBuilder MapChangePasswordEndpoint(this IEndpointRout .WithDescription("Change password"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs index a409436ad..fb0f69459 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordValidator.cs @@ -21,4 +21,4 @@ public ChangePasswordValidator() .Equal(p => p.NewPassword) .WithMessage("Passwords do not match."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs index 5d70c9fd7..a8bc1bbf3 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ConfirmEmail/ConfirmEmailEndpoint.cs @@ -17,4 +17,4 @@ internal static RouteHandlerBuilder MapConfirmEmailEndpoint(this IEndpointRouteB .WithDescription("confirm user email") .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs index 13833d2e7..c24636ee7 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/DeleteUser/DeleteUserEndpoint.cs @@ -18,4 +18,4 @@ internal static RouteHandlerBuilder MapDeleteUserEndpoint(this IEndpointRouteBui .RequirePermission("Permissions.Users.Delete") .WithDescription("delete user profile"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs index 13b54d277..4eac3fca4 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordCommandValidator.cs @@ -9,4 +9,4 @@ public ForgotPasswordCommandValidator() .NotEmpty() .EmailAddress(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs index 4672d44d2..cc74a22b4 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs @@ -42,4 +42,4 @@ internal static RouteHandlerBuilder MapForgotPasswordEndpoint(this IEndpointRout .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/FshUser.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/FshUser.cs index f9c3e7ded..7eddbce8e 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/FshUser.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/FshUser.cs @@ -11,4 +11,4 @@ public class FshUser : IdentityUser public DateTime RefreshTokenExpiryTime { get; set; } public string? ObjectId { get; set; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs index 34601366a..8f0be5dc0 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUser/GetUserEndpoint.cs @@ -18,4 +18,4 @@ internal static RouteHandlerBuilder MapGetUserEndpoint(this IEndpointRouteBuilde .RequirePermission("Permissions.Users.View") .WithDescription("Get another user's profile details by user ID."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs index e0f29ca07..33ff76dd5 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserPermissions/GetUserPermissionsEndpoint.cs @@ -24,4 +24,4 @@ internal static RouteHandlerBuilder MapGetCurrentUserPermissionsEndpoint(this IE .WithSummary("Get current user permissions") .WithDescription("Get current user permissions"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs index 525309c45..018ce5992 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserProfile/GetUserProfileEndpoint.cs @@ -24,4 +24,4 @@ internal static RouteHandlerBuilder MapGetMeEndpoint(this IEndpointRouteBuilder .WithSummary("Get current user information based on token") .WithDescription("Get current user information based on token"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs index b3a2bc940..08a0e77cd 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUserRoles/GetUserRolesEndpoint.cs @@ -18,4 +18,4 @@ internal static RouteHandlerBuilder MapGetUserRolesEndpoint(this IEndpointRouteB .RequirePermission("Permissions.Users.View") .WithDescription("get user roles"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs index bfe89dca8..4662de6d1 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/GetUsers/GetUsersListEndpoint.cs @@ -18,4 +18,4 @@ internal static RouteHandlerBuilder MapGetUsersListEndpoint(this IEndpointRouteB .RequirePermission("Permissions.Users.View") .WithDescription("get users list"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs index 6d115b9eb..39e5c0306 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/RegisterUser/RegisterUserEndpoint.cs @@ -31,4 +31,4 @@ internal static RouteHandlerBuilder MapRegisterUserEndpoint(this IEndpointRouteB .RequirePermission("Permissions.Users.Create") .WithDescription("register user"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs index 9917e3cce..87451c994 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordCommandValidator.cs @@ -10,4 +10,4 @@ public ResetPasswordCommandValidator() RuleFor(x => x.Password).NotEmpty(); RuleFor(x => x.Token).NotEmpty(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs index 1c05cefdc..704dbb8fc 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs @@ -35,4 +35,4 @@ internal static RouteHandlerBuilder MapResetPasswordEndpoint(this IEndpointRoute .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs index fda5269bf..6de6c93ae 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs @@ -35,4 +35,4 @@ internal static RouteHandlerBuilder MapSelfRegisterUserEndpoint(this IEndpointRo .WithDescription("self register user") .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs index 24b442f02..b80dbb88e 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ToggleUserStatus/ToggleUserStatusEndpoint.cs @@ -32,4 +32,4 @@ internal static RouteHandlerBuilder ToggleUserStatusEndpointEndpoint(this IEndpo .AllowAnonymous(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs index 60384819b..a9f840490 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserCommandValidator.cs @@ -38,4 +38,4 @@ public UpdateUserCommandValidator() .Must(x => !(x.DeleteCurrentImage && x.Image is not null)) .WithMessage("You cannot upload a new image and delete the current one simultaneously."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs index 2d7601a5b..74c99e3a5 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UpdateUser/UpdateUserEndpoint.cs @@ -32,4 +32,4 @@ internal static RouteHandlerBuilder MapUpdateUserEndpoint(this IEndpointRouteBui .RequirePermission("Permissions.Users.Update") .WithDescription("update user profile"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UserImageValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UserImageValidator.cs index 8527e998f..129f58b50 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UserImageValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/UserImageValidator.cs @@ -18,4 +18,4 @@ public UserImageValidator(FileType fileType) .Must(data => data.Count <= rules.MaxSizeInMB * 1024 * 1024) .WithMessage($"File must be <= {rules.MaxSizeInMB} MB."); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs index 1e276b960..0d8c46046 100644 --- a/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs @@ -90,4 +90,4 @@ public static IEndpointRouteBuilder MapIdentityEndpoints(this IEndpointRouteBuil TokenGenerationEndpoint.Map(group); return endpoints; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Options/ConfigureJwtBearerOptions.cs b/src/framework/Modules/Identity/Modules.Identity/Options/ConfigureJwtBearerOptions.cs index 71be89e79..fb7d35667 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Options/ConfigureJwtBearerOptions.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Options/ConfigureJwtBearerOptions.cs @@ -76,4 +76,4 @@ public void Configure(string? name, JwtBearerOptions options) } }; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs b/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs index ea99b4959..2aca2233e 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs @@ -18,4 +18,4 @@ public IEnumerable Validate(ValidationContext validationContex yield return new ValidationResult("No Key defined in JwtOptions config", [nameof(Key)]); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs index bb3450df4..7761ec430 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs @@ -58,4 +58,4 @@ public void SetCurrentUserId(string userId) _userId = Guid.Parse(userId); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/IRoleService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/IRoleService.cs index d979300f3..e940f3ab7 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/IRoleService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/IRoleService.cs @@ -9,5 +9,4 @@ public interface IRoleService Task GetWithPermissionsAsync(string id, CancellationToken cancellationToken); Task UpdatePermissionsAsync(string roleId, List permissions); -} - +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/ITokenService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/ITokenService.cs index de1e7aea4..bde1674a6 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/ITokenService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/ITokenService.cs @@ -3,4 +3,4 @@ public interface ITokenService { Task GenerateTokenAsync(string email, string password, string ipAddress, CancellationToken cancellationToken); Task RefreshTokenAsync(string token, string refreshToken, string ipAddress, CancellationToken cancellationToken); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/IUserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/IUserService.cs index 38595f6d6..1bfa52b8f 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/IUserService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/IUserService.cs @@ -30,4 +30,4 @@ public interface IUserService Task ChangePasswordAsync(string password, string newPassword, string confirmNewPassword, string userId); Task AssignRolesAsync(string userId, List userRoles, CancellationToken cancellationToken); Task> GetUserRolesAsync(string userId, CancellationToken cancellationToken); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs index 9084bb2aa..45b2921ef 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs @@ -200,4 +200,4 @@ private ClaimsPrincipal GetPrincipalFromExpiredToken(string token) return principal; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs index 4099318bd..32f673dad 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs @@ -68,4 +68,4 @@ public async Task ChangePasswordAsync(string password, string newPassword, strin throw new CustomException("failed to change password", errors); } } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs index 9aa83426c..3996996c3 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs @@ -50,4 +50,4 @@ public Task InvalidatePermissionCacheAsync(string userId, CancellationToken canc { return cache.RemoveItemAsync(GetPermissionCacheKey(userId), cancellationToken); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs index 54b7fa014..71dc1b0fa 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs @@ -329,4 +329,4 @@ public async Task> GetUserRolesAsync(string userId, Cancellati return userRoles; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs index 1a979ed35..3dbcad274 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs @@ -1,4 +1,4 @@ namespace Tenant.Contracts; public static class TenantConstants { -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs index 27262e2d7..b98f63be1 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs @@ -1,4 +1,4 @@ using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Contracts.v1.ActivateTenant; -public sealed record ActivateTenantCommand(string TenantId) : ICommand; +public sealed record ActivateTenantCommand(string TenantId) : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Data/TenantDbContext.cs b/src/framework/Modules/Tenant/Modules.Tenant/Data/TenantDbContext.cs index 243eceecf..062f952ba 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Data/TenantDbContext.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Data/TenantDbContext.cs @@ -20,4 +20,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().ToTable("Tenants", Schema); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs b/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs index 14074333c..3a6850de1 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs @@ -130,4 +130,4 @@ private static IEnumerable TenantStoreSetup(IApplicationBuilder a return tenants; } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs index 4aad68506..a6246f154 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs @@ -13,4 +13,4 @@ public async Task HandleAsync( var result = await tenantService.ActivateAsync(command.TenantId, cancellationToken); return new ActivateTenantCommandResponse(result, command.TenantId); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs index bf3adbdd9..f1b645396 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandValidator.cs @@ -7,4 +7,4 @@ public sealed class ActivateTenantCommandValidator : AbstractValidator RuleFor(t => t.TenantId) .NotEmpty(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs index 39e3651bf..fd6906c36 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs @@ -18,4 +18,4 @@ public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) .RequirePermission("Permissions.Tenants.Update") .WithDescription("Activate Tenant"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs index 1a2f7dcca..c4a9906dd 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs @@ -18,4 +18,4 @@ public async Task HandleAsync( cancellationToken); return new CreateTenantCommandResponse(tenantId); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs index 861b5c36d..b4d097b0a 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandValidator.cs @@ -26,4 +26,4 @@ public CreateTenantCommandValidator(ITenantService tenantService, IConnectionStr .NotEmpty() .EmailAddress(); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs index c249c036b..6d9cde477 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantEndpoint.cs @@ -20,4 +20,4 @@ public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) .RequirePermission("Permissions.Tenants.Create") .WithDescription("activate tenant"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs index 08f475cc6..7ee25a00b 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs @@ -13,4 +13,4 @@ public async Task HandleAsync( var status = await service.DeactivateAsync(request.TenantId); return new DisableTenantCommandResponse(status); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs index 77754be04..27203d8cc 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs @@ -7,4 +7,4 @@ internal class DisableTenantCommandValidator : AbstractValidator RuleFor(t => t.TenantId) .NotEmpty(); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs index 5726922b5..c53b58876 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantEndpoint.cs @@ -17,4 +17,4 @@ internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) .RequirePermission("Permissions.Tenants.Update") .WithDescription("activate tenant"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs index f4899a692..8bc4d63a4 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdEndpoint.cs @@ -17,4 +17,4 @@ internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) .RequirePermission("Permissions.Tenants.View") .WithDescription("get tenant by id"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs index 0eb5fa16c..ea2d7175e 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs @@ -14,4 +14,4 @@ public async Task HandleAsync(GetTenantByIdQuery que var tenantDto = tenant.Adapt(); return new GetTenantByIdQueryResponse(tenantDto); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs index 8268ac792..eb3b63701 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs @@ -17,4 +17,4 @@ public static RouteHandlerBuilder Map(IEndpointRouteBuilder endpoints) .RequirePermission("Permissions.Tenants.View") .WithDescription("get tenants"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs index c005b0997..9f48bab03 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs @@ -13,4 +13,4 @@ public async Task HandleAsync( var validUpto = await service.UpgradeSubscription(request.Tenant, request.ExtendedExpiryDate); return new UpgradeTenantCommandResponse(validUpto, request.Tenant); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs index 032ac5f30..3caa321e9 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandValidator.cs @@ -9,4 +9,4 @@ public UpgradeTenantCommandValidator() RuleFor(t => t.Tenant).NotEmpty(); RuleFor(t => t.ExtendedExpiryDate).GreaterThan(DateTime.UtcNow); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs index f38bf5a61..819623e5b 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantEndpoint.cs @@ -18,4 +18,4 @@ internal static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) .RequirePermission("Permissions.Tenants.Update") .WithDescription("upgrade tenant subscription"); } -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Services/ITenantService.cs b/src/framework/Modules/Tenant/Modules.Tenant/Services/ITenantService.cs index 86987fc8d..8da8f2f39 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Services/ITenantService.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Services/ITenantService.cs @@ -19,4 +19,4 @@ public interface ITenantService Task DeactivateAsync(string id); Task UpgradeSubscription(string id, DateTime extendedExpiryDate); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs b/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs index 953217f6e..50e48ac98 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs @@ -118,4 +118,4 @@ public async Task UpgradeSubscription(string id, DateTime extendedExpi private async Task GetTenantInfoAsync(string id) => await _tenantStore.TryGetAsync(id).ConfigureAwait(false) ?? throw new NotFoundException($"{typeof(FshTenantInfo).Name} {id} Not Found."); -} +} \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs index 2aecaf9ea..ec93dd6ab 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs @@ -171,4 +171,4 @@ public static IEndpointRouteBuilder MapTenantEndpoints(this IEndpointRouteBuilde return endpoints; } -} +} \ No newline at end of file diff --git a/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs b/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs index a950fb1a5..d704aee8b 100644 --- a/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs +++ b/src/framework/playground/migrations/PostgreSQL/Auditing/20250417072044_Add Auditing Schema.cs @@ -43,4 +43,4 @@ protected override void Down(MigrationBuilder migrationBuilder) name: "Trails", schema: "auditing"); } -} +} \ No newline at end of file diff --git a/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs index 52fc4074d..39944cf0a 100644 --- a/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs +++ b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs @@ -265,4 +265,4 @@ protected override void Down(MigrationBuilder migrationBuilder) name: "Users", schema: "identity"); } -} +} \ No newline at end of file diff --git a/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs b/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs index 77e4945ec..25b831d4a 100644 --- a/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs +++ b/src/framework/playground/migrations/PostgreSQL/Tenant/20250416110812_Add Tenant Schema.cs @@ -47,4 +47,4 @@ protected override void Down(MigrationBuilder migrationBuilder) name: "Tenants", schema: "tenant"); } -} +} \ No newline at end of file From 5efeb9d656ee8dac81e6553b6a2a19902a5566e8 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Fri, 18 Apr 2025 00:31:44 +0530 Subject: [PATCH 44/54] cleanup --- .../GetUserTrailsQueryHandler.cs | 2 +- .../GetUserTrailsQueryValidator.cs | 2 +- .../Caching/CacheServiceExtensions.cs | 4 +++- .../Common/Extensions/EnumExtensions.cs | 19 ++++++++++++++----- .../Common/Extensions/RegexExtensions.cs | 7 +++++-- .../FshInfrastructure.cs | 2 +- ...HangfireCustomBasicAuthenticationFilter.cs | 2 +- .../Logging/Serilog/Extensions.cs | 4 ++-- .../CQRS/Validation/QueryValidation.cs | 2 +- .../RefreshTokenCommandHandler.cs | 2 +- .../RefreshTokenCommandValidator.cs | 2 +- .../AssignUserRolesCommandHandler.cs | 2 +- .../Services/UserService.Permissions.cs | 4 ++-- .../DisableTenantCommandValidator.cs | 2 +- .../GetTenantByIdQueryHandler.cs | 2 +- .../UpgradeTenantCommandHandler.cs | 2 +- .../20250416110641_Add Identity Schema.cs | 4 +++- 17 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs index 01d6a8fc3..86ebddd80 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryHandler.cs @@ -3,7 +3,7 @@ using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Auditing.Features.v1.GetUserTrails; -internal class GetUserTrailsQueryHandler(IAuditService auditService) +internal sealed class GetUserTrailsQueryHandler(IAuditService auditService) : IQueryHandler { public async Task HandleAsync(GetUserTrailsQuery query, CancellationToken cancellationToken = default) diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs index 23cdac918..cb2f5f217 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Features/v1/GetUserTrails/GetUserTrailsQueryValidator.cs @@ -2,7 +2,7 @@ using FSH.Framework.Auditing.Contracts.v1.GetUserTrails; namespace FSH.Framework.Auditing.Features.v1.GetUserTrails; -internal class GetUserTrailsQueryValidator : AbstractValidator +internal sealed class GetUserTrailsQueryValidator : AbstractValidator { public GetUserTrailsQueryValidator() { diff --git a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs index a5b0448dd..08a1cf034 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs @@ -1,4 +1,6 @@ -namespace FSH.Framework.Core.Caching; +using FSH.Framework.Core.Caching; + +namespace FSH.Modules.Common.Core.Caching; public static class CacheServiceExtensions { diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs index b84b4ba12..fb8d8bf1b 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Common/Extensions/EnumExtensions.cs @@ -3,7 +3,7 @@ using System.Text.RegularExpressions; namespace FSH.Framework.Infrastructure.Common.Extensions; -public static class EnumExtensions +public static partial class EnumExtensions { public static string GetDescription(this Enum enumValue) { @@ -12,10 +12,10 @@ public static string GetDescription(this Enum enumValue) if (attr.Length > 0) return ((DescriptionAttribute)attr[0]).Description; string result = enumValue.ToString(); - result = Regex.Replace(result, "([a-z])([A-Z])", "$1 $2"); - result = Regex.Replace(result, "([A-Za-z])([0-9])", "$1 $2"); - result = Regex.Replace(result, "([0-9])([A-Za-z])", "$1 $2"); - result = Regex.Replace(result, "(? GetDescriptionList(this Enum enumValue) string result = enumValue.GetDescription(); return new ReadOnlyCollection(result.Split(',').ToList()); } + + [GeneratedRegex("([a-z])([A-Z])")] + private static partial Regex MyRegex(); + [GeneratedRegex("([A-Za-z])([0-9])")] + private static partial Regex MyRegex1(); + [GeneratedRegex("([0-9])([A-Za-z])")] + private static partial Regex MyRegex2(); + [GeneratedRegex("(? (k, v), + [string k, string v] => (k, v), var v => throw new Exception($"Invalid header format {v}") }; @@ -32,7 +32,7 @@ public static WebApplicationBuilder ConfigureSerilog(this WebApplicationBuilder //To remove the duplicate issue, we can use the below code to get the key and value from the configuration var (otelResourceAttribute, otelResourceAttributeValue) = builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]?.Split('=') switch { - [string k, string v] => (k, v), + [string k, string v] => (k, v), _ => throw new Exception($"Invalid header format {builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]}") }; options.ResourceAttributes.Add(otelResourceAttribute, otelResourceAttributeValue); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs index 1d2391a33..817579dc0 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/QueryValidation.cs @@ -1,7 +1,7 @@ using FSH.Framework.Core.Messaging.CQRS; namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; -internal class QueryValidation : IQueryDispatcher +internal sealed class QueryValidation : IQueryDispatcher { private readonly IQueryDispatcher _inner; private readonly IServiceProvider _serviceProvider; diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs index 24bfc026f..9d5e754c8 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Http; namespace FSH.Framework.Identity.v1.Tokens.RefreshToken; -internal class RefreshTokenCommandHandler( +internal sealed class RefreshTokenCommandHandler( ITokenService tokenService, HttpContext context) : ICommandHandler diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs index 04c2af59d..0d26593a2 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandValidator.cs @@ -2,7 +2,7 @@ using FSH.Framework.Identity.Core.Tokens; namespace FSH.Framework.Identity.v1.Tokens.RefreshToken; -internal class RefreshTokenCommandValidator : AbstractValidator +internal sealed class RefreshTokenCommandValidator : AbstractValidator { public RefreshTokenCommandValidator() { diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs index 8de36bf1e..c1c1a8f9f 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs @@ -3,7 +3,7 @@ using FSH.Framework.Identity.Core.Users; namespace FSH.Framework.Identity.v1.Users.AssignUserRoles; -internal class AssignUserRolesCommandHandler(IUserService _userService) +internal sealed class AssignUserRolesCommandHandler(IUserService _userService) : ICommandHandler { public async Task HandleAsync( diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs index 3996996c3..10da55d63 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Permissions.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Caching; -using FSH.Framework.Core.Exceptions; +using FSH.Framework.Core.Exceptions; using FSH.Framework.Shared.Constants; +using FSH.Modules.Common.Core.Caching; using Microsoft.EntityFrameworkCore; namespace FSH.Framework.Infrastructure.Identity.Users.Services; diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs index 27203d8cc..42d0006cc 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandValidator.cs @@ -2,7 +2,7 @@ using FSH.Framework.Tenant.Contracts.v1.DisableTenant; namespace FSH.Framework.Tenant.Features.v1.DisableTenant; -internal class DisableTenantCommandValidator : AbstractValidator +internal sealed class DisableTenantCommandValidator : AbstractValidator { public DisableTenantCommandValidator() => RuleFor(t => t.TenantId) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs index ea2d7175e..fbb516b39 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs @@ -5,7 +5,7 @@ using Mapster; namespace FSH.Framework.Tenant.Features.v1.GetTenantById; -internal class GetTenantByIdQueryHandler(ITenantService service) +internal sealed class GetTenantByIdQueryHandler(ITenantService service) : IQueryHandler { public async Task HandleAsync(GetTenantByIdQuery query, CancellationToken cancellationToken = default) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs index 9f48bab03..f38bdf2b7 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs @@ -3,7 +3,7 @@ using FSH.Framework.Tenant.Services; namespace FSH.Framework.Tenant.Features.v1.UpgradeTenant; -internal class UpgradeTenantCommandHandler(ITenantService service) +internal sealed class UpgradeTenantCommandHandler(ITenantService service) : ICommandHandler { public async Task HandleAsync( diff --git a/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs index 39944cf0a..d24e0c909 100644 --- a/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs +++ b/src/framework/playground/migrations/PostgreSQL/Identity/20250416110641_Add Identity Schema.cs @@ -8,6 +8,8 @@ namespace FSH.PlayGround.Migrations.PostgreSQL.Identity; /// public partial class AddIdentitySchema : Migration { + private static readonly string[] columns = new[] { "NormalizedName", "TenantId" }; + /// protected override void Up(MigrationBuilder migrationBuilder) { @@ -199,7 +201,7 @@ protected override void Up(MigrationBuilder migrationBuilder) name: "RoleNameIndex", schema: "identity", table: "Roles", - columns: new[] { "NormalizedName", "TenantId" }, + columns: columns, unique: true); migrationBuilder.CreateIndex( From 56e739c00b4a6649ae493f413e166a5d95c017fc Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Fri, 18 Apr 2025 00:40:36 +0530 Subject: [PATCH 45/54] cleanup --- .../Data/Interceptors/AuditInterceptor.cs | 2 +- .../Modules.Common.Core/Caching/CacheServiceExtensions.cs | 2 -- .../Common/Modules.Common.Core/Caching/ICacheService.cs | 2 +- .../Common/Modules.Common.Core/Domain/AuditableEntity.cs | 2 +- .../Common/Modules.Common.Core/Domain/BaseEntity.cs | 4 ++-- .../Domain/Contracts/IAggregateRoot.cs | 2 +- .../Modules.Common.Core/Domain/Contracts/IAuditable.cs | 2 +- .../Modules.Common.Core/Domain/Contracts/IEntity.cs | 2 +- .../Domain/Contracts/ISoftDeletable.cs | 2 +- .../Modules.Common.Core/Exceptions/CustomException.cs | 2 +- .../Modules.Common.Core/Exceptions/ForbiddenException.cs | 3 ++- .../Modules.Common.Core/Exceptions/NotFoundException.cs | 3 ++- .../Exceptions/UnauthorizedException.cs | 3 ++- .../Common/Modules.Common.Core/Modules.Common.Core.csproj | 8 +++++--- .../Common/Modules.Common.Core/Persistence/IRepository.cs | 2 +- .../Specifications/SpecificationBuilderExtensions.cs | 2 +- .../Caching/DistributedCacheService.cs | 2 +- .../Modules.Common.Infrastructure/Caching/Extensions.cs | 3 +-- .../Exceptions/CustomExceptionHandler.cs | 2 +- .../Modules.Common.Infrastructure/Jobs/Extensions.cs | 4 ++-- .../Logging/Serilog/Extensions.cs | 4 ++-- .../Persistence/FshDbContext.cs | 2 +- .../Modules.Identity/Features/v1/Roles/RoleService.cs | 1 + .../Modules.Identity/Services/CurrentUserService.cs | 4 ++-- .../Modules.Identity/Services/UserService.Password.cs | 1 + .../Identity/Modules.Identity/Services/UserService.cs | 3 ++- .../Tenant/Modules.Tenant/Services/TenantService.cs | 1 + 27 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs index fa58e95f4..f56d9de66 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Data/Interceptors/AuditInterceptor.cs @@ -2,9 +2,9 @@ using FSH.Framework.Auditing.Contracts.Enums; using FSH.Framework.Auditing.Contracts.Events.IntegrationEvents; using FSH.Framework.Core.Domain; -using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Core.Messaging.Events; +using FSH.Modules.Common.Core.Domain.Contracts; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; diff --git a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs index 08a1cf034..df86cce67 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Caching/CacheServiceExtensions.cs @@ -1,5 +1,3 @@ -using FSH.Framework.Core.Caching; - namespace FSH.Modules.Common.Core.Caching; public static class CacheServiceExtensions diff --git a/src/framework/Modules/Common/Modules.Common.Core/Caching/ICacheService.cs b/src/framework/Modules/Common/Modules.Common.Core/Caching/ICacheService.cs index c5538d71e..b0c95755b 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Caching/ICacheService.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Caching/ICacheService.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Caching; +namespace FSH.Modules.Common.Core.Caching; public interface ICacheService { diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs index 7a486006d..4e1146e42 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/AuditableEntity.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Domain.Contracts; +using FSH.Modules.Common.Core.Domain.Contracts; namespace FSH.Framework.Core.Domain; diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs index 24ba12ec1..5c96547a4 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/BaseEntity.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Domain.Contracts; -using FSH.Framework.Core.Messaging.Events; +using FSH.Framework.Core.Messaging.Events; +using FSH.Modules.Common.Core.Domain.Contracts; using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations.Schema; diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs index 7c54235fd..9d9d7a5f6 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAggregateRoot.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Domain.Contracts; +namespace FSH.Modules.Common.Core.Domain.Contracts; // Apply this marker interface only to aggregate root entities // Repositories will only work with aggregate roots, not their children diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs index 99aa2972e..8e6590cb8 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IAuditable.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Domain.Contracts; +namespace FSH.Modules.Common.Core.Domain.Contracts; public interface IAuditable { diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs index 2c050eda2..f676924e9 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/IEntity.cs @@ -1,7 +1,7 @@ using FSH.Framework.Core.Messaging.Events; using System.Collections.ObjectModel; -namespace FSH.Framework.Core.Domain.Contracts; +namespace FSH.Modules.Common.Core.Domain.Contracts; public interface IEntity { diff --git a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs index 21ff3bdfb..3c4b210c0 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Domain/Contracts/ISoftDeletable.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Domain.Contracts; +namespace FSH.Modules.Common.Core.Domain.Contracts; public interface ISoftDeletable { diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs index b8670e8b1..3ed5a62ef 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/CustomException.cs @@ -1,6 +1,6 @@ using System.Net; -namespace FSH.Framework.Core.Exceptions; +namespace FSH.Modules.Common.Core.Exceptions; /// /// FullStackHero exception used for consistent error handling across the stack. diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs index 7b49705f6..bb47fd4dc 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/ForbiddenException.cs @@ -1,4 +1,5 @@ -using System.Net; +using FSH.Modules.Common.Core.Exceptions; +using System.Net; namespace FSH.Framework.Core.Exceptions; diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs index 0f322d033..3066beaba 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/NotFoundException.cs @@ -1,4 +1,5 @@ -using System.Net; +using FSH.Modules.Common.Core.Exceptions; +using System.Net; namespace FSH.Framework.Core.Exceptions; diff --git a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs index b807f9886..50b04e36e 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Exceptions/UnauthorizedException.cs @@ -1,4 +1,5 @@ -using System.Net; +using FSH.Modules.Common.Core.Exceptions; +using System.Net; namespace FSH.Framework.Core.Exceptions; diff --git a/src/framework/Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj b/src/framework/Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj index 9f6709e0e..e713d44c2 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj +++ b/src/framework/Modules/Common/Modules.Common.Core/Modules.Common.Core.csproj @@ -3,13 +3,15 @@ FSH.Modules.Common.Core FSH.Modules.Common.Core + + + + + - - - diff --git a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs index a1b59c851..46e2bd8f9 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Persistence/IRepository.cs @@ -1,5 +1,5 @@ using Ardalis.Specification; -using FSH.Framework.Core.Domain.Contracts; +using FSH.Modules.Common.Core.Domain.Contracts; namespace FSH.Framework.Core.Persistence; public interface IRepository : IRepositoryBase diff --git a/src/framework/Modules/Common/Modules.Common.Core/Specifications/SpecificationBuilderExtensions.cs b/src/framework/Modules/Common/Modules.Common.Core/Specifications/SpecificationBuilderExtensions.cs index 84fafe24d..a810aa5a3 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Specifications/SpecificationBuilderExtensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Specifications/SpecificationBuilderExtensions.cs @@ -1,6 +1,6 @@ using Ardalis.Specification; -using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Paging; +using FSH.Modules.Common.Core.Exceptions; using System.Linq.Expressions; using System.Reflection; using System.Text.Json; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs index 6da97a038..ce134cda8 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/DistributedCacheService.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Caching; +using FSH.Modules.Common.Core.Caching; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; using System.Text; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs index 35be5ef2f..2a206f8db 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs @@ -1,5 +1,4 @@ -using FSH.Framework.Core.Caching; -using FSH.Modules.Common.Core.Caching; +using FSH.Modules.Common.Core.Caching; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Serilog; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs index f2f7b0ded..8bd6db732 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Exceptions/CustomExceptionHandler.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Exceptions; +using FSH.Modules.Common.Core.Exceptions; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs index c0d758747..f4a87dd4c 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs @@ -1,7 +1,7 @@ -using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.Jobs; +using FSH.Framework.Core.Jobs; using FSH.Framework.Core.Persistence; using FSH.Framework.Infrastructure.Persistence; +using FSH.Modules.Common.Core.Exceptions; using Hangfire; using Hangfire.PostgreSql; using Microsoft.AspNetCore.Builder; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs index 513c2e64f..96ddbbcbb 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs @@ -22,7 +22,7 @@ public static WebApplicationBuilder ConfigureSerilog(this WebApplicationBuilder { var (key, value) = header.Split('=') switch { - [string k, string v] => (k, v), + [string k, string v] => (k, v), var v => throw new Exception($"Invalid header format {v}") }; @@ -32,7 +32,7 @@ public static WebApplicationBuilder ConfigureSerilog(this WebApplicationBuilder //To remove the duplicate issue, we can use the below code to get the key and value from the configuration var (otelResourceAttribute, otelResourceAttributeValue) = builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]?.Split('=') switch { - [string k, string v] => (k, v), + [string k, string v] => (k, v), _ => throw new Exception($"Invalid header format {builder.Configuration["OTEL_RESOURCE_ATTRIBUTES"]}") }; options.ResourceAttributes.Add(otelResourceAttribute, otelResourceAttributeValue); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs index 896428f74..054ccd29a 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs @@ -1,9 +1,9 @@ using Finbuckle.MultiTenant.Abstractions; using Finbuckle.MultiTenant.EntityFrameworkCore; -using FSH.Framework.Core.Domain.Contracts; using FSH.Framework.Core.Messaging.Events; using FSH.Framework.Core.Persistence; using FSH.Framework.Shared.Multitenancy; +using FSH.Modules.Common.Core.Domain.Contracts; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs index 6dc84f344..0c1ed5cd7 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs @@ -7,6 +7,7 @@ using FSH.Framework.Identity.v1.RoleClaims; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; +using FSH.Modules.Common.Core.Exceptions; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs index 7761ec430..dd9d3fb12 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/CurrentUserService.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Exceptions; -using FSH.Framework.Core.ExecutionContext; +using FSH.Framework.Core.ExecutionContext; using FSH.Framework.Shared.Extensions; +using FSH.Modules.Common.Core.Exceptions; using System.Security.Claims; namespace FSH.Framework.Identity.Infrastructure.Users; diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs index 32f673dad..4db24ae27 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.Password.cs @@ -1,5 +1,6 @@ using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Mail; +using FSH.Modules.Common.Core.Exceptions; using Microsoft.AspNetCore.WebUtilities; using System.Collections.ObjectModel; using System.Text; diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs index 71dc1b0fa..fdce045c6 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs @@ -1,5 +1,4 @@ using Finbuckle.MultiTenant.Abstractions; -using FSH.Framework.Core.Caching; using FSH.Framework.Core.Exceptions; using FSH.Framework.Core.Jobs; using FSH.Framework.Core.Mail; @@ -12,6 +11,8 @@ using FSH.Framework.Infrastructure.Constants; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; +using FSH.Modules.Common.Core.Caching; +using FSH.Modules.Common.Core.Exceptions; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.WebUtilities; using Microsoft.EntityFrameworkCore; diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs b/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs index 50e48ac98..b08f17361 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Services/TenantService.cs @@ -4,6 +4,7 @@ using FSH.Framework.Core.Persistence; using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Contracts.Dtos; +using FSH.Modules.Common.Core.Exceptions; using Mapster; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; From 2fff3b90fe5753ff32a67a8bd4c72ebf153b55f2 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Fri, 18 Apr 2025 21:00:35 +0530 Subject: [PATCH 46/54] invert options --- .../Persistence/DatabaseOptions.cs | 1 + .../Persistence/Extensions.cs | 26 +++++++++++-------- .../Persistence/FshDbContext.cs | 2 +- .../Data/IdentityDbContext.cs | 2 +- .../PlayGround.Api/appsettings.json | 3 ++- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs index d5590f6e5..0b6f12610 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Persistence/DatabaseOptions.cs @@ -5,6 +5,7 @@ public class DatabaseOptions : IValidatableObject { public string Provider { get; set; } = "postgresql"; public string ConnectionString { get; set; } = string.Empty; + public string MigrationsAssembly { get; set; } = string.Empty; public IEnumerable Validate(ValidationContext validationContext) { diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs index 653ec9f8c..68c39467a 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs @@ -12,22 +12,26 @@ public static class Extensions private static readonly ILogger Logger = Log.ForContext(typeof(Extensions)); public static DbContextOptionsBuilder ConfigureDatabase(this DbContextOptionsBuilder builder, string dbProvider, - string connectionString + string connectionString, + string migrationsAssembly ) { builder.ConfigureWarnings(warnings => warnings.Log(RelationalEventId.PendingModelChangesWarning)); return dbProvider.ToUpperInvariant() switch { - DbProviders.PostgreSQL => builder - .UseNpgsql( - connectionString, - e => - { - e.MigrationsAssembly("FSH.PlayGround.Migrations.PostgreSQL"); - }) + DbProviders.PostgreSQL => + builder.UseNpgsql( + connectionString, e => + { + e.MigrationsAssembly(migrationsAssembly); + }) .EnableSensitiveDataLogging(), - DbProviders.MSSQL => builder.UseSqlServer(connectionString, e => - e.MigrationsAssembly("FSH.Starter.WebApi.Migrations.MSSQL")), + DbProviders.MSSQL => + builder.UseSqlServer( + connectionString, e => + { + e.MigrationsAssembly(migrationsAssembly); + }), _ => throw new InvalidOperationException($"DB Provider {dbProvider} is not supported."), }; } @@ -55,7 +59,7 @@ public static IServiceCollection BindDbContext(this IServiceCollection services.AddDbContext((sp, options) => { var dbConfig = sp.GetRequiredService>().Value; - options.ConfigureDatabase(dbConfig.Provider, dbConfig.ConnectionString); + options.ConfigureDatabase(dbConfig.Provider, dbConfig.ConnectionString, dbConfig.MigrationsAssembly); options.AddInterceptors(sp.GetServices()); }); return services; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs index 054ccd29a..2c675f2ff 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/FshDbContext.cs @@ -29,7 +29,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) if (!string.IsNullOrWhiteSpace(multiTenantContextAccessor?.MultiTenantContext.TenantInfo?.ConnectionString)) { - optionsBuilder.ConfigureDatabase(_settings.Provider, multiTenantContextAccessor.MultiTenantContext.TenantInfo.ConnectionString!); + optionsBuilder.ConfigureDatabase(_settings.Provider, multiTenantContextAccessor.MultiTenantContext.TenantInfo.ConnectionString!, _settings.MigrationsAssembly); } } public override async Task SaveChangesAsync(CancellationToken cancellationToken = default) diff --git a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs index fda0fe7f3..c11dfccdd 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbContext.cs @@ -38,7 +38,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!string.IsNullOrWhiteSpace(TenantInfo?.ConnectionString)) { - optionsBuilder.ConfigureDatabase(_settings.Provider, TenantInfo.ConnectionString); + optionsBuilder.ConfigureDatabase(_settings.Provider, TenantInfo.ConnectionString, _settings.MigrationsAssembly); } } } \ No newline at end of file diff --git a/src/framework/playground/PlayGround.Api/appsettings.json b/src/framework/playground/PlayGround.Api/appsettings.json index 1117a1454..773a9a8f6 100644 --- a/src/framework/playground/PlayGround.Api/appsettings.json +++ b/src/framework/playground/PlayGround.Api/appsettings.json @@ -1,7 +1,8 @@ { "DatabaseOptions": { "Provider": "postgresql", - "ConnectionString": "Server=192.168.1.110;Database=phoenix;User Id=postgres;Password=password" + "ConnectionString": "Server=192.168.1.110;Database=phoenix;User Id=postgres;Password=password", + "MigrationsAssembly": "FSH.PlayGround.Migrations.PostgreSQL" }, "OriginOptions": { "OriginUrl": "https://localhost:7000" From 2b87703deb8ac1ef307b9958087691b8d3f89aad Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 22 Apr 2025 01:14:50 +0530 Subject: [PATCH 47/54] cleanup --- .../Modules/Auditing/Modules.Auditing/AuditingModule.cs | 5 ++--- .../Auditing/Modules.Auditing/Data/AuditingDbContext.cs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs index 6a4db07a4..fa257f693 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs @@ -2,7 +2,6 @@ using FSH.Framework.Auditing.Data; using FSH.Framework.Auditing.Features.v1.GetUserTrails; using FSH.Framework.Auditing.Services; -using FSH.Framework.Core.Persistence; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Persistence; using Microsoft.AspNetCore.Builder; @@ -16,11 +15,11 @@ public static class AuditingModule public static IServiceCollection ConfigureAuditingModule(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); - services.AddScoped(); + + services.AddScoped(provider => provider.GetRequiredService()); services.RegisterCommandAndQueryHandlers(typeof(AuditingModule).Assembly); services.AddScoped(); services.BindDbContext(); - services.AddScoped(provider => provider.GetRequiredService()); return services; } diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs index 3ed184bfe..2f523e44c 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/Data/AuditingDbContext.cs @@ -15,7 +15,7 @@ public class AuditingDbContext : FshDbContext, IAuditingDbContext public AuditingDbContext( IMultiTenantContextAccessor multiTenantContextAccessor, DbContextOptions options, - IEventPublisher publisher, + IEventPublisher publisher, IOptions settings) : base(multiTenantContextAccessor, options, publisher, settings) { } protected override void OnModelCreating(ModelBuilder modelBuilder) From db557be0386e11675969279a4f65cf19bccd80bb Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Tue, 22 Apr 2025 11:37:09 +0530 Subject: [PATCH 48/54] add architecture tests --- src/framework/.editorconfig | 3 +- src/framework/Directory.Packages.props | 7 +++++ src/framework/FSH.Framework.sln | 11 ++++++- .../Modules.Auditing/AuditingModule.cs | 4 +-- .../Modules.Auditing/Modules.Auditing.csproj | 6 ++-- .../Messaging/CQRS/ICommand.cs | 2 +- .../Messaging/CQRS/ICommandDispatcher.cs | 4 ++- .../Messaging/CQRS/ICommandHandler.cs | 2 +- .../Messaging/CQRS/IQuery.cs | 4 ++- .../Messaging/CQRS/IRequest.cs | 2 +- .../Messaging/CQRS/CommandDispatcher.cs | 1 + .../Messaging/CQRS/Extensions.cs | 1 + .../CQRS/Validation/CommandValidation.cs | 1 + .../RefreshToken/RefreshTokenCommand.cs | 4 +-- .../TokenGeneration/TokenGenerationCommand.cs | 2 +- .../AssignUserRoles/AssignUserRolesCommand.cs | 4 +-- .../ChangePassword/ChangePasswordCommand.cs | 2 +- .../Users/RegisterUser/RegisterUserCommand.cs | 2 +- .../RefreshTokenCommandHandler.cs | 4 +-- .../TokenGenerationCommandHandler.cs | 6 ++-- .../AssignUserRolesCommandHandler.cs | 4 +-- .../Modules.Identity/IdentityModule.cs | 4 +-- .../ActivateTenant/ActivateTenantCommand.cs | 2 +- .../v1/CreateTenant/CreateTenantCommand.cs | 2 +- .../v1/DisableTenant/DisableTenantCommand.cs | 2 +- .../v1/UpgradeTenant/UpgradeTenantCommand.cs | 2 +- .../ActivateTenantCommandHandler.cs | 4 +-- .../CreateTenantCommandHandler.cs | 4 +-- .../DisableTenantCommandHandler.cs | 4 +-- .../UpgradeTenantCommandHandler.cs | 4 +-- .../Modules.Tenant/Modules.Tenant.csproj | 4 ++- .../Tenant/Modules.Tenant/TenantModule.cs | 4 +-- .../Architecture.Tests.csproj | 29 ++++++++++++++++++ .../Messaging/CommandHandlerNamingTests.cs | 28 +++++++++++++++++ .../Messaging/QueryHandlerNamingTests.cs | 27 +++++++++++++++++ .../ModuleAssemblyLoader.cs | 30 +++++++++++++++++++ .../playground/PlayGround.Api/Program.cs | 6 ++-- 37 files changed, 186 insertions(+), 46 deletions(-) create mode 100644 src/framework/Tests/Architecture.Tests/Architecture.Tests.csproj create mode 100644 src/framework/Tests/Architecture.Tests/Messaging/CommandHandlerNamingTests.cs create mode 100644 src/framework/Tests/Architecture.Tests/Messaging/QueryHandlerNamingTests.cs create mode 100644 src/framework/Tests/Architecture.Tests/ModuleAssemblyLoader.cs diff --git a/src/framework/.editorconfig b/src/framework/.editorconfig index 44ec867d8..6380dfb67 100644 --- a/src/framework/.editorconfig +++ b/src/framework/.editorconfig @@ -293,4 +293,5 @@ 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_diagnostic.CA1711.severity = none -dotnet_diagnostic.CA1040.severity = none \ No newline at end of file +dotnet_diagnostic.CA1040.severity = none +dotnet_diagnostic.CA1707.severity = none \ No newline at end of file diff --git a/src/framework/Directory.Packages.props b/src/framework/Directory.Packages.props index db71b784a..260bda8ba 100644 --- a/src/framework/Directory.Packages.props +++ b/src/framework/Directory.Packages.props @@ -36,6 +36,7 @@ + @@ -97,4 +98,10 @@ + + + + + + \ No newline at end of file diff --git a/src/framework/FSH.Framework.sln b/src/framework/FSH.Framework.sln index abfb177ad..c7d50b965 100644 --- a/src/framework/FSH.Framework.sln +++ b/src/framework/FSH.Framework.sln @@ -44,6 +44,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Auditing", "Modules EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modules.Auditing.Contracts", "Modules\Auditing\Modules.Auditing.Contracts\Modules.Auditing.Contracts.csproj", "{84460CBC-D11D-D584-6F3C-EEDC6966689F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F631F5FA-FCC7-4133-B7DE-0A7E2ED97169}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Architecture.Tests", "Tests\Architecture.Tests\Architecture.Tests.csproj", "{55291917-A598-4DC0-86B4-BD350D8F7C9A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -94,6 +98,10 @@ Global {84460CBC-D11D-D584-6F3C-EEDC6966689F}.Debug|Any CPU.Build.0 = Debug|Any CPU {84460CBC-D11D-D584-6F3C-EEDC6966689F}.Release|Any CPU.ActiveCfg = Release|Any CPU {84460CBC-D11D-D584-6F3C-EEDC6966689F}.Release|Any CPU.Build.0 = Release|Any CPU + {55291917-A598-4DC0-86B4-BD350D8F7C9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55291917-A598-4DC0-86B4-BD350D8F7C9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55291917-A598-4DC0-86B4-BD350D8F7C9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55291917-A598-4DC0-86B4-BD350D8F7C9A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -114,9 +122,10 @@ Global {C39F3653-FC44-4E54-A13F-ECE30DDBE888} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {A47D120F-EA39-7479-5FF1-E8F0B9524F1B} = {C39F3653-FC44-4E54-A13F-ECE30DDBE888} {84460CBC-D11D-D584-6F3C-EEDC6966689F} = {C39F3653-FC44-4E54-A13F-ECE30DDBE888} + {55291917-A598-4DC0-86B4-BD350D8F7C9A} = {F631F5FA-FCC7-4133-B7DE-0A7E2ED97169} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} SolutionGuid = {438A0F87-0F3E-43C4-A352-264E0C21F77B} + SolutionGuid = {A2A6BABD-325C-4482-8830-41058E5D509D} EndGlobalSection EndGlobal diff --git a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs index fa257f693..fa4586f76 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs @@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -namespace FSH.Framework.Auditing.Endpoints; +namespace FSH.Modules.Auditing; public static class AuditingModule { public static IServiceCollection ConfigureAuditingModule(this IServiceCollection services) @@ -36,7 +36,7 @@ public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuil .WithOpenApi() .WithApiVersionSet(apiVersionSet); - GetUserTrailsEndpoint.Map(group); + group.Map(); return endpoints; } diff --git a/src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj b/src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj index c97975449..ccc2253e8 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj +++ b/src/framework/Modules/Auditing/Modules.Auditing/Modules.Auditing.csproj @@ -1,10 +1,10 @@  - FSH.Framework.Auditing - FSH.Framework.Auditing + FSH.Modules.Auditing + FSH.Modules.Auditing - FSH.Framework.Auditing + FSH.Modules.Auditing Auditing module for FullStackHero diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs index 11935bb26..07f340c5b 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommand.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Messaging.CQRS; +namespace FSH.Modules.Common.Core.Messaging.CQRS; // Marker for command requests (intended to modify system state) public interface ICommand : IRequest { } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs index 6edcac07b..7b30f6307 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandDispatcher.cs @@ -1,4 +1,6 @@ -namespace FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; + +namespace FSH.Framework.Core.Messaging.CQRS; public interface ICommandDispatcher { /// diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs index 90f23ef67..325cbf240 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/ICommandHandler.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Messaging.CQRS; +namespace FSH.Modules.Common.Core.Messaging.CQRS; /// /// Handles a command and returns a result. diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs index 6f8e4a66e..c1947494f 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IQuery.cs @@ -1,4 +1,6 @@ -namespace FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; + +namespace FSH.Framework.Core.Messaging.CQRS; // Marker for query requests (intended to return data without modifying state) public interface IQuery : IRequest { } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs index 9e773539e..d4a7e45db 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Messaging/CQRS/IRequest.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Messaging.CQRS; +namespace FSH.Modules.Common.Core.Messaging.CQRS; // Represents a generic request with a response public interface IRequest { } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs index 84b07a38e..10f9eb545 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/CommandDispatcher.cs @@ -1,4 +1,5 @@ using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; using Microsoft.Extensions.DependencyInjection; namespace FSH.Framework.Infrastructure.Messaging.CQRS; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs index 631cc98a5..8c213d2ae 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs @@ -1,5 +1,6 @@ using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Infrastructure.Messaging.CQRS.Validation; +using FSH.Modules.Common.Core.Messaging.CQRS; using Microsoft.Extensions.DependencyInjection; using System.Reflection; diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs index 7fb904d36..f2a73fa74 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Validation/CommandValidation.cs @@ -1,4 +1,5 @@ using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Infrastructure.Messaging.CQRS.Validation; public class CommandValidation : ICommandDispatcher diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs index 198dcd441..ded9217e7 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/RefreshToken/RefreshTokenCommand.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Contracts.v1.Tokens.RefreshToken; +using FSH.Framework.Identity.Contracts.v1.Tokens.RefreshToken; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Identity.Core.Tokens; public record RefreshTokenCommand(string Token, string RefreshToken) diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs index 276798503..3d6811cdc 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Tokens/TokenGeneration/TokenGenerationCommand.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; public record TokenGenerationCommand( diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs index 52ab7c2cf..7501df19b 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/AssignUserRoles/AssignUserRolesCommand.cs @@ -1,5 +1,5 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Core.Roles; +using FSH.Framework.Identity.Core.Roles; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; public sealed class AssignUserRolesCommand : ICommand diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs index a05711bff..e7b8a2cf6 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/ChangePassword/ChangePasswordCommand.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Identity.Contracts.v1.Users.ChangePassword; diff --git a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs index 60805f58d..4c412d0e2 100644 --- a/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs +++ b/src/framework/Modules/Identity/Modules.Identity.Contracts/v1/Users/RegisterUser/RegisterUserCommand.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; using System.Text.Json.Serialization; namespace FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs index 9d5e754c8..921d44c75 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs @@ -1,7 +1,7 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Contracts.v1.Tokens.RefreshToken; +using FSH.Framework.Identity.Contracts.v1.Tokens.RefreshToken; using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Shared.Extensions; +using FSH.Modules.Common.Core.Messaging.CQRS; using Microsoft.AspNetCore.Http; namespace FSH.Framework.Identity.v1.Tokens.RefreshToken; diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs index 133f25b49..70eb9ca70 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/TokenGenerationCommandHandler.cs @@ -1,10 +1,10 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; +using FSH.Framework.Identity.Contracts.v1.Tokens.TokenGeneration; using FSH.Framework.Identity.Core.Tokens; using FSH.Framework.Shared.Extensions; +using FSH.Modules.Common.Core.Messaging.CQRS; using Microsoft.AspNetCore.Http; -namespace FSH.Framework.Identity.v1.Tokens.TokenGeneration; +namespace FSH.Modules.Identity.Features.v1.Tokens.TokenGeneration; public class TokenGenerationCommandHandler( ITokenService tokenService, IHttpContextAccessor contextAccessor) diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs index c1c1a8f9f..0e3ee5cab 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/AssignUserRoles/AssignUserRolesCommandHandler.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; +using FSH.Framework.Identity.Contracts.v1.Users.AssignUserRoles; using FSH.Framework.Identity.Core.Users; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Identity.v1.Users.AssignUserRoles; internal sealed class AssignUserRolesCommandHandler(IUserService _userService) diff --git a/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs index 0d8c46046..9bdd1beac 100644 --- a/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs @@ -27,7 +27,7 @@ using Microsoft.Extensions.DependencyInjection; using System.Reflection; -namespace FSH.Framework.Identity; +namespace FSH.Modules.Identity; public static class IdentityModule { public static IServiceCollection ConfigureIdentityModule(this IServiceCollection services) @@ -87,7 +87,7 @@ public static IEndpointRouteBuilder MapIdentityEndpoints(this IEndpointRouteBuil .WithOpenApi() .WithApiVersionSet(apiVersionSet); - TokenGenerationEndpoint.Map(group); + group.Map(); return endpoints; } } \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs index b98f63be1..26cfa55b8 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/ActivateTenant/ActivateTenantCommand.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Contracts.v1.ActivateTenant; public sealed record ActivateTenantCommand(string TenantId) : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs index f531c81b0..810869db2 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/CreateTenant/CreateTenantCommand.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Contracts.v1.CreateTenant; public sealed record CreateTenantCommand( diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs index 0adbcfe0e..531e88300 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/DisableTenant/DisableTenantCommand.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Contracts.v1.DisableTenant; public sealed record DisableTenantCommand(string TenantId) : ICommand; \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs index 0b76c5d20..fa04352f0 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/UpgradeTenant/UpgradeTenantCommand.cs @@ -1,4 +1,4 @@ -using FSH.Framework.Core.Messaging.CQRS; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; public sealed record UpgradeTenantCommand(string Tenant, DateTime ExtendedExpiryDate) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs index a6246f154..2dab39bd9 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Tenant.Contracts.v1.ActivateTenant; +using FSH.Framework.Tenant.Contracts.v1.ActivateTenant; using FSH.Framework.Tenant.Services; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Features.v1.ActivateTenant; public sealed class ActivateTenantCommandHandler(ITenantService tenantService) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs index c4a9906dd..b529d4f4d 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/CreateTenant/CreateTenantCommandHandler.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Tenant.Contracts.v1.CreateTenant; +using FSH.Framework.Tenant.Contracts.v1.CreateTenant; using FSH.Framework.Tenant.Services; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Features.v1.CreateTenant; public class CreateTenantCommandHandler(ITenantService service) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs index 7ee25a00b..d7d1e7931 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/DisableTenant/DisableTenantCommandHandler.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Tenant.Contracts.v1.DisableTenant; +using FSH.Framework.Tenant.Contracts.v1.DisableTenant; using FSH.Framework.Tenant.Services; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Features.v1.DisableTenant; public class DisableTenantCommandHandler(ITenantService service) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs index f38bdf2b7..5da08a22e 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/UpgradeTenant/UpgradeTenantCommandHandler.cs @@ -1,6 +1,6 @@ -using FSH.Framework.Core.Messaging.CQRS; -using FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; +using FSH.Framework.Tenant.Contracts.v1.UpgradeTenant; using FSH.Framework.Tenant.Services; +using FSH.Modules.Common.Core.Messaging.CQRS; namespace FSH.Framework.Tenant.Features.v1.UpgradeTenant; internal sealed class UpgradeTenantCommandHandler(ITenantService service) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj b/src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj index 1a4cdcc05..484155e39 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj +++ b/src/framework/Modules/Tenant/Modules.Tenant/Modules.Tenant.csproj @@ -9,7 +9,9 @@ enable - + + + diff --git a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs index ec93dd6ab..e337623c5 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs @@ -20,7 +20,7 @@ using Serilog; using System.Reflection; -namespace FSH.Framework.Tenant; +namespace FSH.Modules.Tenant; public static class TenantModule { public static IServiceCollection ConfigureTenantModule(this IServiceCollection services) @@ -162,7 +162,7 @@ public static IEndpointRouteBuilder MapTenantEndpoints(this IEndpointRouteBuilde .WithOpenApi() .WithApiVersionSet(apiVersionSet); - CreateTenantEndpoint.Map(group).AllowAnonymous(); + group.Map().AllowAnonymous(); //DisableTenantEndpoint.Map(group); //GetTenantByIdEndpoint.Map(group); //GetTenantsEndpoint.Map(group); diff --git a/src/framework/Tests/Architecture.Tests/Architecture.Tests.csproj b/src/framework/Tests/Architecture.Tests/Architecture.Tests.csproj new file mode 100644 index 000000000..db166d85d --- /dev/null +++ b/src/framework/Tests/Architecture.Tests/Architecture.Tests.csproj @@ -0,0 +1,29 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/framework/Tests/Architecture.Tests/Messaging/CommandHandlerNamingTests.cs b/src/framework/Tests/Architecture.Tests/Messaging/CommandHandlerNamingTests.cs new file mode 100644 index 000000000..77889ca4e --- /dev/null +++ b/src/framework/Tests/Architecture.Tests/Messaging/CommandHandlerNamingTests.cs @@ -0,0 +1,28 @@ +using FSH.Modules.Common.Core.Messaging.CQRS; + +namespace Architecture.Tests.Messaging; + +public class CommandHandlerNamingTests +{ + [Fact] + public void All_ICommandHandler_Implementations_Should_End_With_CommandHandler() + { + var handlerInterfaceType = typeof(ICommandHandler<,>); + + var assemblies = ModuleAssemblyLoader.GetFshAssemblies(); + + var failures = assemblies + .SelectMany(a => a.GetTypes()) + .Where(t => t is { IsClass: true, IsAbstract: false }) + .Where(t => t.GetInterfaces() + .Any(i => + i.IsGenericType && + i.GetGenericTypeDefinition() == handlerInterfaceType)) + .Where(t => !t.Name.EndsWith("CommandHandler", StringComparison.Ordinal)) + .Select(t => t.FullName ?? t.Name) + .ToList(); + + Assert.True(failures.Count == 0, + $"The following classes do not end with 'CommandHandler': {string.Join(", ", failures)}"); + } +} \ No newline at end of file diff --git a/src/framework/Tests/Architecture.Tests/Messaging/QueryHandlerNamingTests.cs b/src/framework/Tests/Architecture.Tests/Messaging/QueryHandlerNamingTests.cs new file mode 100644 index 000000000..d40306bf7 --- /dev/null +++ b/src/framework/Tests/Architecture.Tests/Messaging/QueryHandlerNamingTests.cs @@ -0,0 +1,27 @@ +using FSH.Framework.Core.Messaging.CQRS; + +namespace Architecture.Tests.Messaging; +public class QueryHandlerNamingTests +{ + [Fact] + public void All_IQueryHandler_Implementations_Should_End_With_QueryHandler() + { + var handlerInterfaceType = typeof(IQueryHandler<,>); + + var assemblies = ModuleAssemblyLoader.GetFshAssemblies(); + + var failures = assemblies + .SelectMany(a => a.GetTypes()) + .Where(t => t is { IsClass: true, IsAbstract: false }) + .Where(t => t.GetInterfaces() + .Any(i => + i.IsGenericType && + i.GetGenericTypeDefinition() == handlerInterfaceType)) + .Where(t => !t.Name.EndsWith("QueryHandler", StringComparison.Ordinal)) + .Select(t => t.FullName ?? t.Name) + .ToList(); + + Assert.True(failures.Count == 0, + $"The following classes do not end with 'QueryHandler': {string.Join(", ", failures)}"); + } +} \ No newline at end of file diff --git a/src/framework/Tests/Architecture.Tests/ModuleAssemblyLoader.cs b/src/framework/Tests/Architecture.Tests/ModuleAssemblyLoader.cs new file mode 100644 index 000000000..9e2308b35 --- /dev/null +++ b/src/framework/Tests/Architecture.Tests/ModuleAssemblyLoader.cs @@ -0,0 +1,30 @@ +using System.Reflection; + +namespace Architecture.Tests; +public static class ModuleAssemblyLoader +{ + private static bool _loaded; + + public static void EnsureModulesLoaded() + { + if (_loaded) return; + + // ✅ Explicitly reference one or more types from each module to force load + _ = typeof(FSH.Modules.Identity.IdentityModule).Assembly; + _ = typeof(FSH.Modules.Tenant.TenantModule).Assembly; + _ = typeof(FSH.Modules.Auditing.AuditingModule).Assembly; + // Add more modules here... + + _loaded = true; + } + + public static IEnumerable GetFshAssemblies() + { + EnsureModulesLoaded(); + + return AppDomain.CurrentDomain.GetAssemblies() + .Where(a => + !a.IsDynamic && + a.FullName?.StartsWith("FSH", StringComparison.Ordinal) == true); + } +} \ No newline at end of file diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index 07545c9a5..9fd8da7e2 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -1,9 +1,9 @@ -using FSH.Framework.Auditing.Endpoints; -using FSH.Framework.Identity; +using FSH.Framework.Auditing; using FSH.Framework.Infrastructure; using FSH.Framework.Infrastructure.Messaging.Events; using FSH.Framework.Infrastructure.OpenApi; -using FSH.Framework.Tenant; +using FSH.Modules.Identity; +using FSH.Modules.Tenant; using Scalar.AspNetCore; using System.Reflection; From 3d91bb2c51d2e223d5191e7df7a01c663fa5aecb Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 23 Apr 2025 15:24:31 +0530 Subject: [PATCH 49/54] dynamic module registration --- .../Modules.Auditing.Contracts.csproj | 4 +- .../Modules.Auditing/AuditingModule.cs | 18 +-- .../Modules/ICoreModule.cs | 4 +- .../Origin/OriginOptions.cs | 2 +- .../Caching/Extensions.cs | 2 +- .../Extensions.cs | 31 ++-- .../Jobs/Extensions.cs | 24 +-- .../Logging/Serilog/Extensions.cs | 2 +- .../Mail/Extensions.cs | 2 +- .../Messaging/CQRS/Extensions.cs | 2 +- .../Messaging/Events/Extensions.cs | 2 +- .../Modules/Extensions.cs | 42 ------ .../Modules/IFrameworkModule.cs | 4 +- .../Modules/IModule.cs | 8 +- .../OpenApi/Extensions.cs | 2 +- .../Persistence/Extensions.cs | 2 +- .../RateLimit/Extensions.cs | 2 +- .../SecurityHeaders/Extensions.cs | 2 +- .../Storage/StorageServiceRegistration.cs | 2 +- .../Data/IdentityDbInitializer.cs | 2 +- .../ChangePassword/ChangePasswordEndpoint.cs | 2 +- .../ForgotPassword/ForgotPasswordEndpoint.cs | 2 +- .../Modules.Identity/IdentityModule.cs | 22 +-- .../Modules.Identity/Services/TokenService.cs | 1 + .../Tenant/Modules.Tenant/Extensions.cs | 118 +++++---------- .../ActivateTenantCommandHandler.cs | 2 +- .../ActivateTenant/ActivateTenantEndpoint.cs | 2 +- .../Tenant/Modules.Tenant/TenantModule.cs | 142 ++++-------------- .../Extensions/ModuleExtensions.cs | 41 +++++ .../playground/PlayGround.Api/Program.cs | 22 +-- 30 files changed, 199 insertions(+), 314 deletions(-) delete mode 100644 src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs create mode 100644 src/framework/PlayGround/PlayGround.Api/Extensions/ModuleExtensions.cs diff --git a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj index 08276423a..ca796ab65 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj +++ b/src/framework/Modules/Auditing/Modules.Auditing.Contracts/Modules.Auditing.Contracts.csproj @@ -1,7 +1,7 @@  - FSH.Framework.Auditing.Contracts - FSH.Framework.Auditing.Contracts + FSH.Modules.Auditing.Contracts + FSH.Modules.Auditing.Contracts diff --git a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs index fa4586f76..e1380b67a 100644 --- a/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs +++ b/src/framework/Modules/Auditing/Modules.Auditing/AuditingModule.cs @@ -2,17 +2,19 @@ using FSH.Framework.Auditing.Data; using FSH.Framework.Auditing.Features.v1.GetUserTrails; using FSH.Framework.Auditing.Services; +using FSH.Framework.Core.Persistence; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Persistence; +using FSH.Modules.Common.Infrastructure.Modules; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace FSH.Modules.Auditing; -public static class AuditingModule +public class AuditingModule : IModule { - public static IServiceCollection ConfigureAuditingModule(this IServiceCollection services) + public void AddModule(IServiceCollection services, IConfiguration config) { ArgumentNullException.ThrowIfNull(services); @@ -20,24 +22,22 @@ public static IServiceCollection ConfigureAuditingModule(this IServiceCollection services.RegisterCommandAndQueryHandlers(typeof(AuditingModule).Assembly); services.AddScoped(); services.BindDbContext(); - return services; + services.AddScoped(); } - public static IEndpointRouteBuilder MapAuditingEndpoints(this IEndpointRouteBuilder endpoints) + public void ConfigureModule(WebApplication app) { - var apiVersionSet = endpoints.NewApiVersionSet() + var apiVersionSet = app.NewApiVersionSet() .HasApiVersion(new ApiVersion(1)) .ReportApiVersions() .Build(); - var group = endpoints + var group = app .MapGroup("api/v{version:apiVersion}/auditing") .WithTags("Auditing") .WithOpenApi() .WithApiVersionSet(apiVersionSet); group.Map(); - - return endpoints; } } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs b/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs index 3e284de1e..04a33e902 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Modules/ICoreModule.cs @@ -1,9 +1,9 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace FSH.Framework.Core.Modules; +namespace FSH.Modules.Common.Core.Modules; public interface ICoreModule { - IServiceCollection AddModuleServices(IServiceCollection services, IConfiguration config); + void AddModule(IServiceCollection services, IConfiguration config); } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs b/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs index 12e0de52c..6be3d4c6a 100644 --- a/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs +++ b/src/framework/Modules/Common/Modules.Common.Core/Origin/OriginOptions.cs @@ -1,4 +1,4 @@ -namespace FSH.Framework.Core.Origin; +namespace FSH.Modules.Common.Core.Origin; public class OriginOptions { diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs index 2a206f8db..8c8eb2156 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Caching/Extensions.cs @@ -7,7 +7,7 @@ namespace FSH.Framework.Infrastructure.Caching; internal static class Extensions { private static readonly ILogger _logger = Log.ForContext(typeof(Extensions)); - internal static IServiceCollection ConfigureCaching(this IServiceCollection services, IConfiguration configuration) + internal static IServiceCollection AddFshCaching(this IServiceCollection services, IConfiguration configuration) { services.AddTransient(); var cacheOptions = configuration.GetSection(nameof(CacheOptions)).Get(); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs index 576db57f3..702f0eceb 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs @@ -1,6 +1,6 @@ using FluentValidation; using FSH.Framework.Core; -using FSH.Framework.Core.Origin; +using FSH.Framework.Infrastructure; using FSH.Framework.Infrastructure.Caching; using FSH.Framework.Infrastructure.Cors; using FSH.Framework.Infrastructure.Exceptions; @@ -14,28 +14,29 @@ using FSH.Framework.Infrastructure.RateLimit; using FSH.Framework.Infrastructure.SecurityHeaders; using FSH.Framework.Infrastructure.Storage; +using FSH.Modules.Common.Core.Origin; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using System.Reflection; -namespace FSH.Framework.Infrastructure; +namespace FSH.Modules.Common.Infrastructure; public static class Extensions { - public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBuilder builder) + public static WebApplicationBuilder AddFshFramework(this WebApplicationBuilder builder) { ArgumentNullException.ThrowIfNull(builder); builder.Services.AddHttpContextAccessor(); - builder.ConfigureSerilog(); - builder.ConfigureDatabase(); + builder.AddFshSerilog(); + builder.AddDatabaseOption(); builder.Services.AddCorsPolicy(builder.Configuration); - builder.Services.ConfigureLocalFileStorage(); - builder.Services.ConfigureOpenApi(); - builder.Services.ConfigureJobs(builder.Configuration); - builder.Services.ConfigureMailing(); - builder.Services.ConfigureCaching(builder.Configuration); + builder.Services.AddLocalFileStorage(); + builder.Services.AddFshOpenApi(); + builder.Services.AddFshJobs(); + builder.Services.AddFshMailing(); + builder.Services.AddFshCaching(builder.Configuration); builder.Services.AddExceptionHandler(); builder.Services.AddProblemDetails(); builder.Services.AddHealthChecks(); @@ -52,16 +53,16 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui builder.Services.AddValidatorsFromAssemblies(assemblies); // register messaging services - builder.Services.RegisterCommandAndQueryDispatchers(); - builder.Services.RegisterInMemoryEventBus(assemblies); + builder.Services.AddCommandAndQueryDispatchers(); + builder.Services.AddInMemoryEventBus(assemblies); - builder.Services.ConfigureRateLimit(builder.Configuration); - builder.Services.ConfigureSecurityHeaders(builder.Configuration); + builder.Services.AddRateLimiting(builder.Configuration); + builder.Services.AddSecurityHeaders(builder.Configuration); return builder; } - public static WebApplication UseFshFramework(this WebApplication app) + public static WebApplication ConfigureFshFramework(this WebApplication app) { app.UseRateLimit(); app.UseSecurityHeaders(); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs index f4a87dd4c..f689d56be 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Jobs/Extensions.cs @@ -12,21 +12,23 @@ namespace FSH.Framework.Infrastructure.Jobs; internal static class Extensions { - internal static IServiceCollection ConfigureJobs(this IServiceCollection services, IConfiguration configuration) + internal static IServiceCollection AddFshJobs(this IServiceCollection services) { - var dbOptions = configuration.GetSection(nameof(DatabaseOptions)).Get() ?? - throw new CustomException("database options cannot be null"); - - services.AddHangfireServer(o => + services.AddHangfireServer(options => { - o.HeartbeatInterval = TimeSpan.FromSeconds(30); - o.Queues = ["default", "email"]; - o.WorkerCount = 5; - o.SchedulePollingInterval = TimeSpan.FromSeconds(30); + options.HeartbeatInterval = TimeSpan.FromSeconds(30); + options.Queues = ["default", "email"]; + options.WorkerCount = 5; + options.SchedulePollingInterval = TimeSpan.FromSeconds(30); }); services.AddHangfire((provider, config) => { + var dbOptions = provider + .GetRequiredService() + .GetSection(nameof(DatabaseOptions)) + .Get() ?? throw new CustomException("Database options not found"); + switch (dbOptions.Provider.ToUpperInvariant()) { case DbProviders.PostgreSQL: @@ -41,7 +43,7 @@ internal static IServiceCollection ConfigureJobs(this IServiceCollection service break; default: - throw new CustomException($"hangfire storage provider {dbOptions.Provider} is not supported"); + throw new CustomException($"Hangfire storage provider {dbOptions.Provider} is not supported"); } config.UseFilter(new FshJobFilter(provider)); @@ -49,9 +51,11 @@ internal static IServiceCollection ConfigureJobs(this IServiceCollection service }); services.AddTransient(); + return services; } + internal static IApplicationBuilder UseJobDashboard(this IApplicationBuilder app, IConfiguration config) { var hangfireOptions = config.GetSection(nameof(HangfireOptions)).Get() ?? new HangfireOptions(); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs index 96ddbbcbb..e617d827c 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Logging/Serilog/Extensions.cs @@ -7,7 +7,7 @@ namespace FSH.Framework.Infrastructure.Logging.Serilog; public static class Extensions { - public static WebApplicationBuilder ConfigureSerilog(this WebApplicationBuilder builder) + public static WebApplicationBuilder AddFshSerilog(this WebApplicationBuilder builder) { ArgumentNullException.ThrowIfNull(builder); builder.Host.UseSerilog((context, logger) => diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs index 7ce9c9131..27a659c43 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Mail/Extensions.cs @@ -4,7 +4,7 @@ namespace FSH.Framework.Infrastructure.Mail; internal static class Extensions { - internal static IServiceCollection ConfigureMailing(this IServiceCollection services) + internal static IServiceCollection AddFshMailing(this IServiceCollection services) { services.AddTransient(); services.AddOptions().BindConfiguration(nameof(MailOptions)); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs index 8c213d2ae..7bc0b8ebd 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/CQRS/Extensions.cs @@ -7,7 +7,7 @@ namespace FSH.Framework.Infrastructure.Messaging.CQRS; public static class Extensions { - public static IServiceCollection RegisterCommandAndQueryDispatchers(this IServiceCollection services) + public static IServiceCollection AddCommandAndQueryDispatchers(this IServiceCollection services) { // Register dispatchers services.AddScoped(); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs index ffdcdd818..d649a01b2 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Messaging/Events/Extensions.cs @@ -5,7 +5,7 @@ namespace FSH.Framework.Infrastructure.Messaging.Events; public static class Extensions { - public static IServiceCollection RegisterInMemoryEventBus(this IServiceCollection services, params Assembly[] assemblies) + public static IServiceCollection AddInMemoryEventBus(this IServiceCollection services, params Assembly[] assemblies) { services.AddScoped(); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs deleted file mode 100644 index 109287164..000000000 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/Extensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using System.Reflection; - -namespace FSH.Framework.Infrastructure.Modules; -public static class Extensions -{ - public static IServiceCollection AddFrameworkModules( - this IServiceCollection services, - IConfiguration config, - params Assembly[] assemblies) - { - var moduleTypes = assemblies - .SelectMany(a => a.GetTypes()) - .Where(t => typeof(IFrameworkModule).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract) - .ToList(); - - foreach (var type in moduleTypes) - { - var module = (IFrameworkModule)Activator.CreateInstance(type)!; - module.AddModuleServices(services, config); - services.AddSingleton(module); // Store for endpoint mapping later - } - - return services; - } - - public static IApplicationBuilder MapFrameworkModuleEndpoints(this IApplicationBuilder app) - { - var modules = app.ApplicationServices.GetServices(); - var endpoints = app as IEndpointRouteBuilder; - - foreach (var module in modules) - { - module.MapEndpoints(endpoints!); - } - - return app; - } -} \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs index e69a7db0d..8405a2c00 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IFrameworkModule.cs @@ -1,4 +1,6 @@ -namespace FSH.Framework.Infrastructure.Modules; +using FSH.Modules.Common.Infrastructure.Modules; + +namespace FSH.Framework.Infrastructure.Modules; public interface IFrameworkModule : IModule { } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IModule.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IModule.cs index 912e6860e..bb531bc3c 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IModule.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Modules/IModule.cs @@ -1,8 +1,8 @@ -using FSH.Framework.Core.Modules; -using Microsoft.AspNetCore.Routing; +using FSH.Modules.Common.Core.Modules; +using Microsoft.AspNetCore.Builder; -namespace FSH.Framework.Infrastructure.Modules; +namespace FSH.Modules.Common.Infrastructure.Modules; public interface IModule : ICoreModule { - IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints); + void ConfigureModule(WebApplication app); } \ No newline at end of file diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs index 485148a42..cd84f9fef 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs @@ -8,7 +8,7 @@ namespace FSH.Framework.Infrastructure.OpenApi; public static class Extensions { - public static IServiceCollection ConfigureOpenApi(this IServiceCollection services) + public static IServiceCollection AddFshOpenApi(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); //services.AddEndpointsApiExplorer(); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs index 68c39467a..cffedd772 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Persistence/Extensions.cs @@ -36,7 +36,7 @@ string migrationsAssembly }; } - public static WebApplicationBuilder ConfigureDatabase(this WebApplicationBuilder builder) + public static WebApplicationBuilder AddDatabaseOption(this WebApplicationBuilder builder) { ArgumentNullException.ThrowIfNull(builder); builder.Services.AddOptions() diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs index c18ea3e02..83900b52d 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/RateLimit/Extensions.cs @@ -10,7 +10,7 @@ namespace FSH.Framework.Infrastructure.RateLimit; public static class Extensions { - internal static IServiceCollection ConfigureRateLimit(this IServiceCollection services, IConfiguration config) + internal static IServiceCollection AddRateLimiting(this IServiceCollection services, IConfiguration config) { services.Configure(config.GetSection(nameof(RateLimitOptions))); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs index 17d4cf71e..d13ab44b9 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/SecurityHeaders/Extensions.cs @@ -7,7 +7,7 @@ namespace FSH.Framework.Infrastructure.SecurityHeaders; public static class Extensions { - internal static IServiceCollection ConfigureSecurityHeaders(this IServiceCollection services, IConfiguration config) + internal static IServiceCollection AddSecurityHeaders(this IServiceCollection services, IConfiguration config) { services.Configure(config.GetSection(nameof(SecurityHeaderOptions))); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs index 3c4a5689b..b80b2bcd5 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Storage/StorageServiceRegistration.cs @@ -4,7 +4,7 @@ namespace FSH.Framework.Infrastructure.Storage; public static class StorageServiceRegistration { - public static IServiceCollection ConfigureLocalFileStorage(this IServiceCollection services) + public static IServiceCollection AddLocalFileStorage(this IServiceCollection services) { // You can later use config["Storage:Provider"] to swap between implementations services.AddScoped(); diff --git a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs index f287310b6..68ad9215e 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs @@ -1,11 +1,11 @@ using Finbuckle.MultiTenant.Abstractions; -using FSH.Framework.Core.Origin; using FSH.Framework.Core.Persistence; using FSH.Framework.Identity.Infrastructure.Roles; using FSH.Framework.Identity.Infrastructure.Users; using FSH.Framework.Identity.v1.RoleClaims; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; +using FSH.Modules.Common.Core.Origin; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs index b02e7dffa..6950f1308 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ChangePassword/ChangePasswordEndpoint.cs @@ -1,9 +1,9 @@ using FluentValidation; using FluentValidation.Results; -using FSH.Framework.Core.Origin; using FSH.Framework.Identity.Contracts.v1.Users.ChangePassword; using FSH.Framework.Identity.Core.Users; using FSH.Framework.Shared.Extensions; +using FSH.Modules.Common.Core.Origin; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs index cc74a22b4..ccccd8e74 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs @@ -1,9 +1,9 @@ using FluentValidation; using FluentValidation.Results; -using FSH.Framework.Core.Origin; using FSH.Framework.Identity.Core.Users; using FSH.Framework.Identity.Endpoints.v1.Users.ForgotPassword; using FSH.Framework.Shared.Constants; +using FSH.Modules.Common.Core.Origin; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs index 9bdd1beac..981199631 100644 --- a/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs +++ b/src/framework/Modules/Identity/Modules.Identity/IdentityModule.cs @@ -15,22 +15,24 @@ using FSH.Framework.Infrastructure.Auth; using FSH.Framework.Infrastructure.Auth.Jwt; using FSH.Framework.Infrastructure.Identity.Roles; +using FSH.Framework.Infrastructure.Identity.Roles.Endpoints; using FSH.Framework.Infrastructure.Identity.Users.Services; using FSH.Framework.Infrastructure.Messaging.CQRS; using FSH.Framework.Infrastructure.Persistence; using FSH.Framework.Modules.Identity.Contracts; +using FSH.Modules.Common.Infrastructure.Modules; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.Reflection; namespace FSH.Modules.Identity; -public static class IdentityModule +public class IdentityModule : IModule { - public static IServiceCollection ConfigureIdentityModule(this IServiceCollection services) + public void AddModule(IServiceCollection services, IConfiguration config) { ArgumentNullException.ThrowIfNull(services); @@ -48,8 +50,6 @@ public static IServiceCollection ConfigureIdentityModule(this IServiceCollection { services.AddScoped(result.InterfaceType, result.ValidatorType); } - - services.AddScoped(); services.AddSingleton(); services.AddScoped(); @@ -71,23 +71,23 @@ public static IServiceCollection ConfigureIdentityModule(this IServiceCollection .AddEntityFrameworkStores() .AddDefaultTokenProviders(); services.ConfigureJwtAuth(); - return services; } - public static IEndpointRouteBuilder MapIdentityEndpoints(this IEndpointRouteBuilder endpoints) + public void ConfigureModule(WebApplication app) { - var apiVersionSet = endpoints.NewApiVersionSet() + var apiVersionSet = app.NewApiVersionSet() .HasApiVersion(new ApiVersion(1)) .ReportApiVersions() .Build(); - var group = endpoints + var group = app .MapGroup("api/v{version:apiVersion}/identity") .WithTags("Identity") .WithOpenApi() .WithApiVersionSet(apiVersionSet); - group.Map(); - return endpoints; + TokenGenerationEndpoint.Map(group).AllowAnonymous(); + GetRolesEndpoint.MapGetRolesEndpoint(group); + GetRoleByIdEndpoint.MapGetRoleEndpoint(group); } } \ No newline at end of file diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs index 45b2921ef..de9a008fc 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs @@ -44,6 +44,7 @@ public async Task GenerateTokenAsync( { var currentTenant = _multiTenantContextAccessor!.MultiTenantContext.TenantInfo; if (currentTenant == null) throw new UnauthorizedException(); + if (string.IsNullOrWhiteSpace(currentTenant.Id) || await _userManager.FindByEmailAsync(email.Trim().Normalize()) is not { } user || !await _userManager.CheckPasswordAsync(user, password)) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs b/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs index 3a6850de1..abd3644c5 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs @@ -1,63 +1,55 @@ using Finbuckle.MultiTenant; using Finbuckle.MultiTenant.Abstractions; -using Finbuckle.MultiTenant.Stores.DistributedCacheStore; using FSH.Framework.Core.Persistence; -using FSH.Framework.Infrastructure.Persistence; -using FSH.Framework.Infrastructure.Persistence.Services; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Data; -using FSH.Framework.Tenant.Services; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Serilog; namespace FSH.Framework.Tenant; -internal static class Extensions +public static class Extensions { - public static IServiceCollection ConfigureMultitenancy(this IServiceCollection services) + private static IEnumerable TenantStoreSetup(IApplicationBuilder app) { - ArgumentNullException.ThrowIfNull(services); - services.AddTransient(); - services.BindDbContext(); - services - .AddMultiTenant(config => - { - // to save database calls to resolve tenant - // this was happening for every request earlier, leading to ineffeciency - config.Events.OnTenantResolveCompleted = async (context) => - { - if (context.MultiTenantContext.StoreInfo is null) return; - if (context.MultiTenantContext.StoreInfo.StoreType != typeof(DistributedCacheStore)) - { - var sp = ((HttpContext)context.Context!).RequestServices; - var distributedCacheStore = sp - .GetService>>()! - .FirstOrDefault(s => s.GetType() == typeof(DistributedCacheStore)); + var scope = app.ApplicationServices.CreateScope(); - await distributedCacheStore!.TryAddAsync(context.MultiTenantContext.TenantInfo!); - } - await Task.FromResult(0); - }; - }) - .WithClaimStrategy(FshClaims.Tenant) - .WithHeaderStrategy(TenantConstants.Identifier) - .WithDelegateStrategy(async context => - { - if (context is not HttpContext httpContext) - return null; - if (!httpContext.Request.Query.TryGetValue(FshClaims.Tenant, out var tenantIdentifier) || string.IsNullOrEmpty(tenantIdentifier)) - return null; - return await Task.FromResult(tenantIdentifier.ToString()); - }) - .WithDistributedCacheStore(TimeSpan.FromMinutes(60)) - .WithEFCoreStore(); - services.AddScoped(); - return services; + // tenant master schema migration + var tenantDbContext = scope.ServiceProvider.GetRequiredService(); + if (tenantDbContext.Database.GetPendingMigrations().Any()) + { + tenantDbContext.Database.Migrate(); + Log.Information("applied database migrations for tenant module"); + } + + // default tenant seeding + if (tenantDbContext.TenantInfo.Find(TenantConstants.Root.Id) is null) + { + var rootTenant = new FshTenantInfo( + TenantConstants.Root.Id, + TenantConstants.Root.Name, + string.Empty, + TenantConstants.Root.EmailAddress); + + rootTenant.SetValidity(DateTime.UtcNow.AddYears(1)); + tenantDbContext.TenantInfo.Add(rootTenant); + tenantDbContext.SaveChanges(); + Log.Information("configured default tenant data"); + } + + // get all tenants from store + var tenantStore = scope.ServiceProvider.GetRequiredService>(); + var tenants = tenantStore.GetAllAsync().Result; + + //dispose scope + scope.Dispose(); + + return tenants; } - public static WebApplication UseMultitenancy(this WebApplication app) + public static WebApplication ConfigureMultiTenantDatabases(this WebApplication app) { ArgumentNullException.ThrowIfNull(app); app.UseMultiTenant(); @@ -70,7 +62,6 @@ public static WebApplication UseMultitenancy(this WebApplication app) return app; } - private static IApplicationBuilder SetupTenantDatabases(this IApplicationBuilder app, IEnumerable tenants) { foreach (var tenant in tenants) @@ -95,39 +86,4 @@ private static IApplicationBuilder SetupTenantDatabases(this IApplicationBuilder } return app; } - - private static IEnumerable TenantStoreSetup(IApplicationBuilder app) - { - var scope = app.ApplicationServices.CreateScope(); - - // tenant master schema migration - var tenantDbContext = scope.ServiceProvider.GetRequiredService(); - if (tenantDbContext.Database.GetPendingMigrations().Any()) - { - tenantDbContext.Database.Migrate(); - } - - // default tenant seeding - if (tenantDbContext.TenantInfo.Find(TenantConstants.Root.Id) is null) - { - var rootTenant = new FshTenantInfo( - TenantConstants.Root.Id, - TenantConstants.Root.Name, - string.Empty, - TenantConstants.Root.EmailAddress); - - rootTenant.SetValidity(DateTime.UtcNow.AddYears(1)); - tenantDbContext.TenantInfo.Add(rootTenant); - tenantDbContext.SaveChanges(); - } - - // get all tenants from store - var tenantStore = scope.ServiceProvider.GetRequiredService>(); - var tenants = tenantStore.GetAllAsync().Result; - - //dispose scope - scope.Dispose(); - - return tenants; - } -} \ No newline at end of file +} diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs index 2dab39bd9..2e8e7a98d 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantCommandHandler.cs @@ -2,7 +2,7 @@ using FSH.Framework.Tenant.Services; using FSH.Modules.Common.Core.Messaging.CQRS; -namespace FSH.Framework.Tenant.Features.v1.ActivateTenant; +namespace FSH.Modules.Tenant.Features.v1.ActivateTenant; public sealed class ActivateTenantCommandHandler(ITenantService tenantService) : ICommandHandler { diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs index fd6906c36..77d0450cc 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/ActivateTenant/ActivateTenantEndpoint.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; -namespace FSH.Framework.Tenant.Features.v1.ActivateTenant; +namespace FSH.Modules.Tenant.Features.v1.ActivateTenant; public static class ActivateTenantEndpoint { public static RouteHandlerBuilder Map(this IEndpointRouteBuilder endpoints) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs index e337623c5..aec445e8e 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs @@ -9,166 +9,88 @@ using FSH.Framework.Infrastructure.Persistence.Services; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; +using FSH.Framework.Tenant; using FSH.Framework.Tenant.Data; -using FSH.Framework.Tenant.Features.v1.CreateTenant; +using FSH.Framework.Tenant.Features.v1.GetTenantById; using FSH.Framework.Tenant.Services; +using FSH.Modules.Common.Infrastructure.Modules; +using FSH.Modules.Tenant.Features.v1.ActivateTenant; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; -using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Serilog; using System.Reflection; namespace FSH.Modules.Tenant; -public static class TenantModule + +public class TenantModule : IModule { - public static IServiceCollection ConfigureTenantModule(this IServiceCollection services) + public void AddModule(IServiceCollection services, IConfiguration config) { ArgumentNullException.ThrowIfNull(services); + services.RegisterCommandAndQueryHandlers(Assembly.GetExecutingAssembly()); - var assemblies = new Assembly[] - { - typeof(TenantModule).Assembly - }; - services.AddValidatorsFromAssemblies(assemblies, includeInternalTypes: true); + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly(), includeInternalTypes: true); services.AddTransient(); + services.BindDbContext(); + services - .AddMultiTenant(config => + .AddMultiTenant(options => { - // to save database calls to resolve tenant - // this was happening for every request earlier, leading to ineffeciency - config.Events.OnTenantResolveCompleted = async (context) => + options.Events.OnTenantResolveCompleted = async context => { if (context.MultiTenantContext.StoreInfo is null) return; if (context.MultiTenantContext.StoreInfo.StoreType != typeof(DistributedCacheStore)) { var sp = ((HttpContext)context.Context!).RequestServices; - var distributedCacheStore = sp - .GetService>>()! + var distributedStore = sp + .GetRequiredService>>() .FirstOrDefault(s => s.GetType() == typeof(DistributedCacheStore)); - await distributedCacheStore!.TryAddAsync(context.MultiTenantContext.TenantInfo!); + await distributedStore!.TryAddAsync(context.MultiTenantContext.TenantInfo!); } - await Task.FromResult(0); + await Task.CompletedTask; }; }) .WithClaimStrategy(FshClaims.Tenant) .WithHeaderStrategy(TenantConstants.Identifier) .WithDelegateStrategy(async context => { - if (context is not HttpContext httpContext) - return null; - if (!httpContext.Request.Query.TryGetValue("tenant", out var tenantIdentifier) || string.IsNullOrEmpty(tenantIdentifier)) + if (context is not HttpContext httpContext) return null; + + if (!httpContext.Request.Query.TryGetValue("tenant", out var tenantIdentifier) || + string.IsNullOrEmpty(tenantIdentifier)) return null; + return await Task.FromResult(tenantIdentifier.ToString()); }) .WithDistributedCacheStore(TimeSpan.FromMinutes(60)) .WithEFCoreStore(); - services.AddScoped(); - return services; - } - public static WebApplication UseFshMultiTenancy(this WebApplication app) - { - ArgumentNullException.ThrowIfNull(app); - app.UseMultiTenant(); - - // set up tenant store - var tenants = TenantStoreSetup(app); - - // set up tenant databases - app.SetupTenantDatabases(tenants); - - // register endpoints - app.MapTenantEndpoints(); - return app; - } - - private static IApplicationBuilder SetupTenantDatabases(this IApplicationBuilder app, IEnumerable tenants) - { - foreach (var tenant in tenants) - { - // create a scope for tenant - using var tenantScope = app.ApplicationServices.CreateScope(); - - //set current tenant so that the right connection string is used - tenantScope.ServiceProvider.GetRequiredService() - .MultiTenantContext = new MultiTenantContext() - { - TenantInfo = tenant - }; - // using the scope, perform migrations / seeding - var initializers = tenantScope.ServiceProvider.GetServices(); - foreach (var initializer in initializers) - { - initializer.MigrateAsync(CancellationToken.None).Wait(); - initializer.SeedAsync(CancellationToken.None).Wait(); - } - } - return app; + services.AddScoped(); } - private static IEnumerable TenantStoreSetup(IApplicationBuilder app) + public void ConfigureModule(WebApplication app) { - var scope = app.ApplicationServices.CreateScope(); - - // tenant master schema migration - var tenantDbContext = scope.ServiceProvider.GetRequiredService(); - if (tenantDbContext.Database.GetPendingMigrations().Any()) - { - tenantDbContext.Database.Migrate(); - Log.Information("applied database migrations for tenant module"); - } - - // default tenant seeding - if (tenantDbContext.TenantInfo.Find(TenantConstants.Root.Id) is null) - { - var rootTenant = new FshTenantInfo( - TenantConstants.Root.Id, - TenantConstants.Root.Name, - string.Empty, - TenantConstants.Root.EmailAddress); + app.ConfigureMultiTenantDatabases(); - rootTenant.SetValidity(DateTime.UtcNow.AddYears(1)); - tenantDbContext.TenantInfo.Add(rootTenant); - tenantDbContext.SaveChanges(); - Log.Information("configured default tenant data"); - } - - // get all tenants from store - var tenantStore = scope.ServiceProvider.GetRequiredService>(); - var tenants = tenantStore.GetAllAsync().Result; - - //dispose scope - scope.Dispose(); - - return tenants; - } - - public static IEndpointRouteBuilder MapTenantEndpoints(this IEndpointRouteBuilder endpoints) - { - var apiVersionSet = endpoints.NewApiVersionSet() + var versionSet = app.NewApiVersionSet() .HasApiVersion(new ApiVersion(1)) .ReportApiVersions() .Build(); - var group = endpoints - .MapGroup("api/v{version:apiVersion}/tenants") + var group = app.MapGroup("api/v{version:apiVersion}/tenants") .WithTags("Tenants") .WithOpenApi() - .WithApiVersionSet(apiVersionSet); + .WithApiVersionSet(versionSet); - group.Map().AllowAnonymous(); //DisableTenantEndpoint.Map(group); - //GetTenantByIdEndpoint.Map(group); + GetTenantByIdEndpoint.Map(group); //GetTenantsEndpoint.Map(group); //UpgradeTenantEndpoint.Map(group); - //ActivateTenantEndpoint.Map(group); - - return endpoints; + ActivateTenantEndpoint.Map(group); } -} \ No newline at end of file +} diff --git a/src/framework/PlayGround/PlayGround.Api/Extensions/ModuleExtensions.cs b/src/framework/PlayGround/PlayGround.Api/Extensions/ModuleExtensions.cs new file mode 100644 index 000000000..2ab67f5f7 --- /dev/null +++ b/src/framework/PlayGround/PlayGround.Api/Extensions/ModuleExtensions.cs @@ -0,0 +1,41 @@ +using FSH.Modules.Common.Infrastructure.Modules; +using System.Reflection; + +namespace FSH.PlayGround.Api.Extensions; + +public static class ModuleExtensions +{ + public static IServiceCollection AddModules(this IServiceCollection services, IConfiguration config) + { + var moduleTypes = typeof(ModuleExtensions).Assembly + .GetReferencedAssemblies() + .Select(Assembly.Load) + .SelectMany(a => a.GetTypes()) + .Where(t => typeof(IModule).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); + + foreach (var type in moduleTypes) + { + Console.WriteLine($"[AddModule] Registering module: {type.FullName}"); + var module = (IModule)Activator.CreateInstance(type)!; + module.AddModule(services, config); + } + + return services; + } + + public static WebApplication ConfigureModules(this WebApplication app) + { + var moduleTypes = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => a.GetTypes()) + .Where(t => typeof(IModule).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); + + foreach (var type in moduleTypes) + { + Console.WriteLine($"[ConfigureModule] Configuring module: {type.FullName}"); + var module = (IModule)Activator.CreateInstance(type)!; + module.ConfigureModule(app); + } + + return app; + } +} diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index 9fd8da7e2..e53987004 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -1,9 +1,11 @@ -using FSH.Framework.Auditing; -using FSH.Framework.Infrastructure; using FSH.Framework.Infrastructure.Messaging.Events; using FSH.Framework.Infrastructure.OpenApi; +using FSH.Framework.Tenant; +using FSH.Modules.Auditing; +using FSH.Modules.Common.Infrastructure; using FSH.Modules.Identity; using FSH.Modules.Tenant; +using FSH.PlayGround.Api.Extensions; using Scalar.AspNetCore; using System.Reflection; @@ -12,10 +14,9 @@ { options.AddDocumentTransformer(); }); -builder.ConfigureFshFramework(); -builder.Services.ConfigureTenantModule(); -builder.Services.ConfigureIdentityModule(); -builder.Services.ConfigureAuditingModule(); + +builder.AddFshFramework(); +builder.Services.AddModules(builder.Configuration); var assemblies = new Assembly[] { @@ -23,7 +24,7 @@ typeof(IdentityModule).Assembly, typeof(AuditingModule).Assembly }; -builder.Services.RegisterInMemoryEventBus(assemblies); +builder.Services.AddInMemoryEventBus(assemblies); var app = builder.Build(); if (app.Environment.IsDevelopment()) @@ -33,11 +34,10 @@ app.MapScalarApiReference(options => options.AddDocuments(versions)); } -app.UseFshMultiTenancy(); -app.UseFshFramework(); -app.MapIdentityEndpoints(); -app.MapAuditingEndpoints(); +app.ConfigureMultiTenantDatabases(); +app.ConfigureFshFramework(); +app.ConfigureModules(); app.UseHttpsRedirection(); await app.RunAsync(); \ No newline at end of file From e5d5474b3ebaa6b506b7bd71a9da63da042b7d8a Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 23 Apr 2025 15:53:38 +0530 Subject: [PATCH 50/54] add tenant endpoints --- .../Modules/Tenant/Modules.Tenant/TenantModule.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs index aec445e8e..5ff27c800 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs @@ -11,7 +11,11 @@ using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant; using FSH.Framework.Tenant.Data; +using FSH.Framework.Tenant.Features.v1.CreateTenant; +using FSH.Framework.Tenant.Features.v1.DisableTenant; using FSH.Framework.Tenant.Features.v1.GetTenantById; +using FSH.Framework.Tenant.Features.v1.GetTenants; +using FSH.Framework.Tenant.Features.v1.UpgradeTenant; using FSH.Framework.Tenant.Services; using FSH.Modules.Common.Infrastructure.Modules; using FSH.Modules.Tenant.Features.v1.ActivateTenant; @@ -87,10 +91,11 @@ public void ConfigureModule(WebApplication app) .WithOpenApi() .WithApiVersionSet(versionSet); - //DisableTenantEndpoint.Map(group); + DisableTenantEndpoint.Map(group); GetTenantByIdEndpoint.Map(group); - //GetTenantsEndpoint.Map(group); - //UpgradeTenantEndpoint.Map(group); + GetTenantsEndpoint.Map(group); + UpgradeTenantEndpoint.Map(group); ActivateTenantEndpoint.Map(group); + CreateTenantEndpoint.Map(group); } } From db7a1a44aefa879d30e5e77c8ad4d7c950e7312f Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 23 Apr 2025 22:11:04 +0530 Subject: [PATCH 51/54] fix auth bug --- .../Identity/Modules.Identity/Options/JwtOptions.cs | 10 ++++++++++ .../v1/GetTenantById/GetTenantByIdQuery.cs | 3 ++- .../v1/GetTenantById/GetTenantByIdQueryResponse.cs | 4 ---- .../v1/GetTenants/GetTenantsQuery.cs | 3 ++- .../v1/GetTenants/GetTenantsQueryResponse.cs | 4 ---- .../v1/GetTenantById/GetTenantByIdQueryHandler.cs | 9 ++++----- .../Features/v1/GetTenants/GetTenantsQueryHandler.cs | 6 +++--- .../playground/PlayGround.Api/appsettings.json | 4 +++- 8 files changed, 24 insertions(+), 19 deletions(-) delete mode 100644 src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs delete mode 100644 src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs diff --git a/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs b/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs index 2aca2233e..82e47ac81 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Options/JwtOptions.cs @@ -17,5 +17,15 @@ public IEnumerable Validate(ValidationContext validationContex { yield return new ValidationResult("No Key defined in JwtOptions config", [nameof(Key)]); } + + if (string.IsNullOrEmpty(Issuer)) + { + yield return new ValidationResult("No Issuer defined in JwtOptions config", [nameof(Key)]); + } + + if (string.IsNullOrEmpty(Audience)) + { + yield return new ValidationResult("No Audience defined in JwtOptions config", [nameof(Key)]); + } } } \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs index b50159844..6d664d9c0 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQuery.cs @@ -1,4 +1,5 @@ using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.Dtos; namespace FSH.Framework.Tenant.Contracts.v1.GetTenantById; -public sealed record GetTenantByIdQuery(string TenantId) : IQuery; \ No newline at end of file +public sealed record GetTenantByIdQuery(string TenantId) : IQuery; \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs deleted file mode 100644 index daf1cf346..000000000 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenantById/GetTenantByIdQueryResponse.cs +++ /dev/null @@ -1,4 +0,0 @@ -using FSH.Framework.Tenant.Contracts.Dtos; - -namespace FSH.Framework.Tenant.Contracts.v1.GetTenantById; -public sealed record GetTenantByIdQueryResponse(TenantDto Tenant); \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs index 0d81ff447..b4758ca81 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQuery.cs @@ -1,4 +1,5 @@ using FSH.Framework.Core.Messaging.CQRS; +using FSH.Framework.Tenant.Contracts.Dtos; namespace FSH.Framework.Tenant.Contracts.v1.GetTenants; -public sealed record GetTenantsQuery : IQuery; \ No newline at end of file +public sealed record GetTenantsQuery : IQuery>; \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs deleted file mode 100644 index bd8363035..000000000 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/v1/GetTenants/GetTenantsQueryResponse.cs +++ /dev/null @@ -1,4 +0,0 @@ -using FSH.Framework.Tenant.Contracts.Dtos; - -namespace FSH.Framework.Tenant.Contracts.v1.GetTenants; -public sealed record GetTenantsQueryResponse(IReadOnlyCollection Tenants); \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs index fbb516b39..8185c47a9 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenantById/GetTenantByIdQueryHandler.cs @@ -5,13 +5,12 @@ using Mapster; namespace FSH.Framework.Tenant.Features.v1.GetTenantById; -internal sealed class GetTenantByIdQueryHandler(ITenantService service) - : IQueryHandler +public sealed class GetTenantByIdQueryHandler(ITenantService service) + : IQueryHandler { - public async Task HandleAsync(GetTenantByIdQuery query, CancellationToken cancellationToken = default) + public async Task HandleAsync(GetTenantByIdQuery query, CancellationToken cancellationToken = default) { var tenant = await service.GetByIdAsync(query.TenantId); - var tenantDto = tenant.Adapt(); - return new GetTenantByIdQueryResponse(tenantDto); + return tenant.Adapt(); } } \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs index 7b89ec35f..3ad2f2301 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs @@ -7,11 +7,11 @@ namespace FSH.Framework.Tenant.Features.v1.GetTenants; public sealed class GetTenantsQueryHandler(ITenantService service) - : IQueryHandler + : IQueryHandler> { - public async Task HandleAsync(GetTenantsQuery query, CancellationToken cancellationToken = default) + public async Task> HandleAsync(GetTenantsQuery query, CancellationToken cancellationToken = default) { var tenants = await service.GetAllAsync(); - return new GetTenantsQueryResponse(tenants.Adapt>()); + return tenants.Adapt>(); } } \ No newline at end of file diff --git a/src/framework/playground/PlayGround.Api/appsettings.json b/src/framework/playground/PlayGround.Api/appsettings.json index 773a9a8f6..048148f52 100644 --- a/src/framework/playground/PlayGround.Api/appsettings.json +++ b/src/framework/playground/PlayGround.Api/appsettings.json @@ -18,7 +18,9 @@ "JwtOptions": { "Key": "QsJbczCNysv/5SGh+U7sxedX8C07TPQPBdsnSDKZ/aE=", "TokenExpirationInMinutes": 60, - "RefreshTokenExpirationInDays": 7 + "RefreshTokenExpirationInDays": 7, + "Audience": "playground.api", + "Issuer": "playground.api" }, "MailOptions": { "From": "mukesh@fullstackhero.net", From 9d833dcf9399d6d9c892c3781d42be8b711fddd7 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 24 Apr 2025 07:24:50 +0530 Subject: [PATCH 52/54] cleanup --- .../{TenantConstants.cs => MutiTenancyConstants.cs} | 4 ++-- .../Multitenancy/FshTenantInfo.cs | 6 +++--- .../Modules.Identity/Data/IdentityDbInitializer.cs | 7 ++++--- .../Modules.Identity/Features/v1/Roles/RoleService.cs | 3 ++- .../v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs | 4 ++-- .../v1/Users/ResetPassword/ResetPasswordEndpoint.cs | 4 ++-- .../Users/SelfRegistration/SelfRegisterUserEndpoint.cs | 4 ++-- .../Identity/Modules.Identity/Services/TokenService.cs | 3 ++- .../Identity/Modules.Identity/Services/UserService.cs | 7 ++++--- .../Tenant/Modules.Tenant.Contracts/TenantConstants.cs | 6 +++++- .../Modules/Tenant/Modules.Tenant/Extensions.cs | 10 +++++----- .../Features/v1/GetTenants/GetTenantsEndpoint.cs | 4 +++- .../Features/v1/GetTenants/GetTenantsQueryHandler.cs | 5 ++++- .../Modules/Tenant/Modules.Tenant/TenantModule.cs | 3 ++- 14 files changed, 42 insertions(+), 28 deletions(-) rename src/framework/Modules/Common/Modules.Common.Shared/Constants/{TenantConstants.cs => MutiTenancyConstants.cs} (81%) diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs b/src/framework/Modules/Common/Modules.Common.Shared/Constants/MutiTenancyConstants.cs similarity index 81% rename from src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs rename to src/framework/Modules/Common/Modules.Common.Shared/Constants/MutiTenancyConstants.cs index 37fbf799b..37a17379c 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Constants/TenantConstants.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Constants/MutiTenancyConstants.cs @@ -1,5 +1,5 @@ -namespace FSH.Framework.Shared.Constants; -public static class TenantConstants +namespace FSH.Modules.Common.Shared.Constants; +public static class MutiTenancyConstants { public static class Root { diff --git a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs index 743fffbcf..3698ab9b4 100644 --- a/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs +++ b/src/framework/Modules/Common/Modules.Common.Shared/Multitenancy/FshTenantInfo.cs @@ -1,5 +1,5 @@ using Finbuckle.MultiTenant.Abstractions; -using FSH.Framework.Shared.Constants; +using FSH.Modules.Common.Shared.Constants; namespace FSH.Framework.Shared.Multitenancy; public class FshTenantInfo : ITenantInfo, IFshTenantInfo @@ -42,7 +42,7 @@ public void SetValidity(in DateTime validTill) => public void Activate() { - if (Id == TenantConstants.Root.Id) + if (Id == MutiTenancyConstants.Root.Id) { throw new InvalidOperationException("Invalid Tenant"); } @@ -52,7 +52,7 @@ public void Activate() public void Deactivate() { - if (Id == TenantConstants.Root.Id) + if (Id == MutiTenancyConstants.Root.Id) { throw new InvalidOperationException("Invalid Tenant"); } diff --git a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs index 68ad9215e..579486c09 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs @@ -6,6 +6,7 @@ using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using FSH.Modules.Common.Core.Origin; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -57,7 +58,7 @@ private async Task SeedRolesAsync() { await AssignPermissionsToRoleAsync(context, FshPermissions.Admin, role); - if (multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id == TenantConstants.Root.Id) + if (multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id == MutiTenancyConstants.Root.Id) { await AssignPermissionsToRoleAsync(context, FshPermissions.Root, role); } @@ -115,13 +116,13 @@ private async Task SeedAdminUserAsync() PhoneNumberConfirmed = true, NormalizedEmail = multiTenantContextAccessor.MultiTenantContext.TenantInfo?.AdminEmail!.ToUpperInvariant(), NormalizedUserName = adminUserName.ToUpperInvariant(), - ImageUrl = new Uri(originSettings.Value.OriginUrl! + TenantConstants.Root.DefaultProfilePicture), + ImageUrl = new Uri(originSettings.Value.OriginUrl! + MutiTenancyConstants.Root.DefaultProfilePicture), IsActive = true }; logger.LogInformation("Seeding Default Admin User for '{TenantId}' Tenant.", multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id); var password = new PasswordHasher(); - adminUser.PasswordHash = password.HashPassword(adminUser, TenantConstants.DefaultPassword); + adminUser.PasswordHash = password.HashPassword(adminUser, MutiTenancyConstants.DefaultPassword); await userManager.CreateAsync(adminUser); } diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs index 0c1ed5cd7..6ffca551e 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs @@ -8,6 +8,7 @@ using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using FSH.Modules.Common.Core.Exceptions; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; @@ -86,7 +87,7 @@ public async Task UpdatePermissionsAsync(string roleId, List per throw new CustomException("operation not permitted"); } - if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id != TenantConstants.Root.Id) + if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id != MutiTenancyConstants.Root.Id) { // Remove Root Permissions if the Role is not created for Root Tenant. permissions.RemoveAll(u => u.StartsWith("Permissions.Root.", StringComparison.InvariantCultureIgnoreCase)); diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs index ccccd8e74..eb43d3515 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ForgotPassword/ForgotPasswordEndpoint.cs @@ -2,8 +2,8 @@ using FluentValidation.Results; using FSH.Framework.Identity.Core.Users; using FSH.Framework.Identity.Endpoints.v1.Users.ForgotPassword; -using FSH.Framework.Shared.Constants; using FSH.Modules.Common.Core.Origin; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -16,7 +16,7 @@ public static class ForgotPasswordEndpoint { internal static RouteHandlerBuilder MapForgotPasswordEndpoint(this IEndpointRouteBuilder endpoints) { - return endpoints.MapPost("/forgot-password", async (HttpRequest request, [FromHeader(Name = TenantConstants.Identifier)] string tenant, [FromBody] ForgotPasswordCommand command, IOptions settings, IValidator validator, IUserService userService, CancellationToken cancellationToken) => + return endpoints.MapPost("/forgot-password", async (HttpRequest request, [FromHeader(Name = MutiTenancyConstants.Identifier)] string tenant, [FromBody] ForgotPasswordCommand command, IOptions settings, IValidator validator, IUserService userService, CancellationToken cancellationToken) => { ValidationResult result = await validator.ValidateAsync(command, cancellationToken); if (!result.IsValid) diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs index 704dbb8fc..20dec931b 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/ResetPassword/ResetPasswordEndpoint.cs @@ -2,7 +2,7 @@ using FluentValidation.Results; using FSH.Framework.Identity.Core.Users; using FSH.Framework.Identity.Endpoints.v1.Users.ResetPassword; -using FSH.Framework.Shared.Constants; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -16,7 +16,7 @@ internal static RouteHandlerBuilder MapResetPasswordEndpoint(this IEndpointRoute { return endpoints.MapPost("/reset-password", async ([FromBody] ResetPasswordCommand command, - [FromHeader(Name = TenantConstants.Identifier)] string tenant, + [FromHeader(Name = MutiTenancyConstants.Identifier)] string tenant, IValidator validator, IUserService userService, CancellationToken cancellationToken) => { diff --git a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs index 6de6c93ae..f038bccc4 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Features/v1/Users/SelfRegistration/SelfRegisterUserEndpoint.cs @@ -1,7 +1,7 @@ using FSH.Framework.Identity.Core.Users; using FSH.Framework.Identity.Endpoints.v1.Users.RegisterUser; using FSH.Framework.Shared.Authorization; -using FSH.Framework.Shared.Constants; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -13,7 +13,7 @@ public static class SelfRegisterUserEndpoint internal static RouteHandlerBuilder MapSelfRegisterUserEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints.MapPost("/self-register", (RegisterUserCommand request, - [FromHeader(Name = TenantConstants.Identifier)] string tenant, + [FromHeader(Name = MutiTenancyConstants.Identifier)] string tenant, IUserService service, HttpContext context, CancellationToken cancellationToken) => diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs index de9a008fc..aa7bf5861 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/TokenService.cs @@ -9,6 +9,7 @@ using FSH.Framework.Identity.Options; using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; @@ -62,7 +63,7 @@ public async Task GenerateTokenAsync( throw new UnauthorizedException("email not confirmed"); } - if (currentTenant.Id != TenantConstants.Root.Id) + if (currentTenant.Id != MutiTenancyConstants.Root.Id) { if (!currentTenant.IsActive) { diff --git a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs index fdce045c6..b85fb48fa 100644 --- a/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs +++ b/src/framework/Modules/Identity/Modules.Identity/Services/UserService.cs @@ -13,6 +13,7 @@ using FSH.Framework.Shared.Multitenancy; using FSH.Modules.Common.Core.Caching; using FSH.Modules.Common.Core.Exceptions; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.WebUtilities; using Microsoft.EntityFrameworkCore; @@ -253,7 +254,7 @@ private async Task GetEmailVerificationUriAsync(FshUser user, string ori string verificationUri = QueryHelpers.AddQueryString(endpointUri.ToString(), QueryStringKeys.UserId, user.Id); verificationUri = QueryHelpers.AddQueryString(verificationUri, QueryStringKeys.Code, code); verificationUri = QueryHelpers.AddQueryString(verificationUri, - TenantConstants.Identifier, + MutiTenancyConstants.Identifier, multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id!); return verificationUri; } @@ -273,9 +274,9 @@ public async Task AssignRolesAsync(string userId, List user // Check if user is not Root Tenant Admin // Edge Case : there are chances for other tenants to have users with the same email as that of Root Tenant Admin. Probably can add a check while User Registration - if (user.Email == TenantConstants.Root.EmailAddress) + if (user.Email == MutiTenancyConstants.Root.EmailAddress) { - if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id == TenantConstants.Root.Id) + if (multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id == MutiTenancyConstants.Root.Id) { throw new CustomException("action not permitted"); } diff --git a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs index 3dbcad274..755632470 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant.Contracts/TenantConstants.cs @@ -1,4 +1,8 @@ -namespace Tenant.Contracts; +namespace FSH.Modules.Tenant.Contracts; public static class TenantConstants { + public static class Permissions + { + public const string View = "Permissions.Tenants.View"; + } } \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs b/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs index abd3644c5..b5d6a7f74 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Extensions.cs @@ -1,9 +1,9 @@ using Finbuckle.MultiTenant; using Finbuckle.MultiTenant.Abstractions; using FSH.Framework.Core.Persistence; -using FSH.Framework.Shared.Constants; using FSH.Framework.Shared.Multitenancy; using FSH.Framework.Tenant.Data; +using FSH.Modules.Common.Shared.Constants; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; @@ -25,13 +25,13 @@ private static IEnumerable TenantStoreSetup(IApplicationBuilder a } // default tenant seeding - if (tenantDbContext.TenantInfo.Find(TenantConstants.Root.Id) is null) + if (tenantDbContext.TenantInfo.Find(MutiTenancyConstants.Root.Id) is null) { var rootTenant = new FshTenantInfo( - TenantConstants.Root.Id, - TenantConstants.Root.Name, + MutiTenancyConstants.Root.Id, + MutiTenancyConstants.Root.Name, string.Empty, - TenantConstants.Root.EmailAddress); + MutiTenancyConstants.Root.EmailAddress); rootTenant.SetValidity(DateTime.UtcNow.AddYears(1)); tenantDbContext.TenantInfo.Add(rootTenant); diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs index eb3b63701..883f53e52 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsEndpoint.cs @@ -1,6 +1,7 @@ using FSH.Framework.Core.Messaging.CQRS; using FSH.Framework.Shared.Authorization; using FSH.Framework.Tenant.Contracts.v1.GetTenants; +using FSH.Modules.Tenant.Contracts; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -13,8 +14,9 @@ public static RouteHandlerBuilder Map(IEndpointRouteBuilder endpoints) return endpoints.MapGet("/", (IQueryDispatcher dispatcher) => dispatcher.SendAsync(new GetTenantsQuery())) .WithName(nameof(GetTenantsEndpoint)) + .HasApiVersion(1) .WithSummary("get tenants") - .RequirePermission("Permissions.Tenants.View") + .RequirePermission(TenantConstants.Permissions.View) .WithDescription("get tenants"); } } \ No newline at end of file diff --git a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs index 3ad2f2301..bca7b6616 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/Features/v1/GetTenants/GetTenantsQueryHandler.cs @@ -9,7 +9,10 @@ namespace FSH.Framework.Tenant.Features.v1.GetTenants; public sealed class GetTenantsQueryHandler(ITenantService service) : IQueryHandler> { - public async Task> HandleAsync(GetTenantsQuery query, CancellationToken cancellationToken = default) + public async Task> HandleAsync( + GetTenantsQuery query, + CancellationToken cancellationToken = default + ) { var tenants = await service.GetAllAsync(); return tenants.Adapt>(); diff --git a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs index 5ff27c800..25eaef212 100644 --- a/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs +++ b/src/framework/Modules/Tenant/Modules.Tenant/TenantModule.cs @@ -18,6 +18,7 @@ using FSH.Framework.Tenant.Features.v1.UpgradeTenant; using FSH.Framework.Tenant.Services; using FSH.Modules.Common.Infrastructure.Modules; +using FSH.Modules.Common.Shared.Constants; using FSH.Modules.Tenant.Features.v1.ActivateTenant; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; @@ -60,7 +61,7 @@ public void AddModule(IServiceCollection services, IConfiguration config) }; }) .WithClaimStrategy(FshClaims.Tenant) - .WithHeaderStrategy(TenantConstants.Identifier) + .WithHeaderStrategy(MutiTenancyConstants.Identifier) .WithDelegateStrategy(async context => { if (context is not HttpContext httpContext) return null; From 793fb4bee85cf891c6af5b54b6e00520e01e7ffb Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 30 Apr 2025 21:46:35 +0530 Subject: [PATCH 53/54] add swagger --- .../Extensions.cs | 2 +- .../OpenApi/Extensions.cs | 52 ++++++++++--------- .../playground/PlayGround.Api/Program.cs | 3 -- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs index 702f0eceb..968b57908 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/Extensions.cs @@ -68,7 +68,7 @@ public static WebApplication ConfigureFshFramework(this WebApplication app) app.UseSecurityHeaders(); app.UseExceptionHandler(); app.UseCorsPolicy(); - //app.UseOpenApi(); + app.UseOpenApi(); app.UseJobDashboard(app.Configuration); app.UseRouting(); app.UseStaticFiles(); diff --git a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs index cd84f9fef..cdadc29c9 100644 --- a/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs +++ b/src/framework/Modules/Common/Modules.Common.Infrastructure/OpenApi/Extensions.cs @@ -2,6 +2,9 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerUI; namespace FSH.Framework.Infrastructure.OpenApi; @@ -11,30 +14,30 @@ public static class Extensions public static IServiceCollection AddFshOpenApi(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); - //services.AddEndpointsApiExplorer(); - //services.AddTransient, ConfigureSwaggerOptions>(); - //services - // .AddSwaggerGen(options => - // { - // options.OperationFilter(); - // options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme - // { - // Type = SecuritySchemeType.Http, - // Scheme = "bearer", - // BearerFormat = "JWT", - // Description = "JWT Authorization header using the Bearer scheme." - // }); - // options.AddSecurityRequirement(new OpenApiSecurityRequirement - // { - // { - // new OpenApiSecurityScheme - // { - // Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" } - // }, - // Array.Empty() - // } - // }); - // }); + services.AddEndpointsApiExplorer(); + services.AddTransient, ConfigureSwaggerOptions>(); + services + .AddSwaggerGen(options => + { + options.OperationFilter(); + options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.Http, + Scheme = "bearer", + BearerFormat = "JWT", + Description = "JWT Authorization header using the Bearer scheme." + }); + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" } + }, + Array.Empty() + } + }); + }); services .AddApiVersioning(options => { @@ -46,6 +49,7 @@ public static IServiceCollection AddFshOpenApi(this IServiceCollection services) .AddApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; + options.SubstituteApiVersionInUrl = true; }) .EnableApiVersionBinding(); return services; diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index e53987004..51524b651 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -6,7 +6,6 @@ using FSH.Modules.Identity; using FSH.Modules.Tenant; using FSH.PlayGround.Api.Extensions; -using Scalar.AspNetCore; using System.Reflection; var builder = WebApplication.CreateBuilder(args); @@ -30,8 +29,6 @@ if (app.Environment.IsDevelopment()) { app.MapOpenApi(); - string[] versions = ["v1", "v2"]; - app.MapScalarApiReference(options => options.AddDocuments(versions)); } From 4422a5f08f851015b32d49d4c04d463e859db901 Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Wed, 30 Apr 2025 21:48:15 +0530 Subject: [PATCH 54/54] scalar --- src/framework/playground/PlayGround.Api/Program.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/framework/playground/PlayGround.Api/Program.cs b/src/framework/playground/PlayGround.Api/Program.cs index 51524b651..e53987004 100644 --- a/src/framework/playground/PlayGround.Api/Program.cs +++ b/src/framework/playground/PlayGround.Api/Program.cs @@ -6,6 +6,7 @@ using FSH.Modules.Identity; using FSH.Modules.Tenant; using FSH.PlayGround.Api.Extensions; +using Scalar.AspNetCore; using System.Reflection; var builder = WebApplication.CreateBuilder(args); @@ -29,6 +30,8 @@ if (app.Environment.IsDevelopment()) { app.MapOpenApi(); + string[] versions = ["v1", "v2"]; + app.MapScalarApiReference(options => options.AddDocuments(versions)); }