diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 7380956107..cc150dac1b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,9 +4,9 @@ ## Project Summary -Unity is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 9.1.3** with **.NET 9.0**, targeting **PostgreSQL 17**. The primary application code lives in `applications/Unity.GrantManager/`. +Unity is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 10.3** with **.NET 10.0**, targeting **PostgreSQL 17**. The primary application code lives in `applications/Unity.GrantManager/`. -**Key stack:** .NET 9 · ABP 9.1.3 · EF Core 9.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · AutoMapper · Cypress (E2E) +**Key stack:** .NET 10 · ABP 10.3 · EF Core 10.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · Mapperly · Cypress (E2E) ## Repository Structure @@ -21,7 +21,7 @@ documentation/ ← Technical docs ## Key Conventions - **ABP Framework** modular monolith with DDD layered architecture -- **AutoMapper** for DTO mapping (not Mapperly) +- **Mapperly** for DTO mapping (not AutoMapper) - **Razor Pages** UI with custom ABP theme (Unity.Theme.UX2) - Multi-tenant architecture with separate host/tenant database contexts - `dev` → `test` → `main` branch promotion flow @@ -39,6 +39,6 @@ All PRs must pass `dotnet build` and `dotnet test` before merge. The CI runs all ## Do NOT -- Use Mapperly patterns — this project uses AutoMapper +- Use AutoMapper patterns — this project uses Mapperly - Create repositories for child entities — only aggregate roots get repositories - Put business logic in application services — use domain entities/services diff --git a/applications/Unity.GrantManager/.github/AGENTS.md b/applications/Unity.GrantManager/.github/AGENTS.md index 649e86322f..f27502fc65 100644 --- a/applications/Unity.GrantManager/.github/AGENTS.md +++ b/applications/Unity.GrantManager/.github/AGENTS.md @@ -21,4 +21,4 @@ Pick the agent that matches your workflow stage and provide: 2. Target module(s) and files. 3. Constraints (tenant scope, security, deadline, non-functional requirements). -Each agent enforces ABP layering, AutoMapper usage, localization, and test conventions from repository instructions and skills. \ No newline at end of file +Each agent enforces ABP layering, Mapperly usage, localization, and test conventions from repository instructions and skills. diff --git a/applications/Unity.GrantManager/.github/agents/application-service-designer.agent.md b/applications/Unity.GrantManager/.github/agents/application-service-designer.agent.md index 0126a8087a..9b5c73a0e7 100644 --- a/applications/Unity.GrantManager/.github/agents/application-service-designer.agent.md +++ b/applications/Unity.GrantManager/.github/agents/application-service-designer.agent.md @@ -1,6 +1,6 @@ --- name: application-service-designer -description: Designs application contracts, DTOs, authorization, and AutoMapper mapping plans. +description: Designs application contracts, DTOs, authorization, and Mapperly mapping plans. --- # ABP Application Service Designer Agent @@ -22,7 +22,7 @@ Produce ABP-compliant service contracts and implementation plans using DTO-first 1. Propose or update `I*AppService` method signatures. 2. Define DTOs per method intent (create, update, get, list). 3. Identify authorization requirements and permission constants. -4. Define AutoMapper profile changes. +4. Define Mapperly mapper changes. 5. Define validation and business-exception boundaries. ## Output Format @@ -40,4 +40,4 @@ Produce ABP-compliant service contracts and implementation plans using DTO-first - Follow `.github/instructions/csharp.instructions.md`. - Methods must be async and end with `Async`. - Accept/return DTOs only, never entities. -- Use AutoMapper with `ObjectMapper.Map<>()`, never Mapperly. +- Use Mapperly with `ObjectMapper.Map<>()`, never AutoMapper. Mapper classes inherit `MapperBase` or `TwoWayMapperBase` and are decorated with `[Mapper]`. diff --git a/applications/Unity.GrantManager/.github/agents/feature-planner.agent.md b/applications/Unity.GrantManager/.github/agents/feature-planner.agent.md index a52030b62f..39f53ab988 100644 --- a/applications/Unity.GrantManager/.github/agents/feature-planner.agent.md +++ b/applications/Unity.GrantManager/.github/agents/feature-planner.agent.md @@ -144,5 +144,5 @@ Rules: - Enforce module dependency direction from `.github/skills/unity-module-structure/SKILL.md`. - Enforce ABP app/domain rules from `.github/instructions/csharp.instructions.md`. -- Do not use Mapperly. Use AutoMapper. +- Do not use AutoMapper. Use Mapperly (`[Mapper]` attribute, `MapperBase`). - Do not place business rules in controllers or app services. diff --git a/applications/Unity.GrantManager/.github/agents/pr-readiness.agent.md b/applications/Unity.GrantManager/.github/agents/pr-readiness.agent.md index 88bd2466a0..07b855f51b 100644 --- a/applications/Unity.GrantManager/.github/agents/pr-readiness.agent.md +++ b/applications/Unity.GrantManager/.github/agents/pr-readiness.agent.md @@ -38,4 +38,4 @@ Evaluate if a branch is ready for PR against ABP architecture, policy, and CI ex - Follow `.github/copilot-instructions.md`. - Require `dotnet build Unity.GrantManager.sln --no-restore` and `dotnet test Unity.GrantManager.sln --no-build` readiness. - Enforce ABP module layering rules from `.github/skills/unity-module-structure/SKILL.md`. -- Enforce AutoMapper, localization, and permissions conventions. +- Enforce Mapperly, localization, and permissions conventions. diff --git a/applications/Unity.GrantManager/.github/agents/pre-readiness-deep.agent.md b/applications/Unity.GrantManager/.github/agents/pre-readiness-deep.agent.md index bd78117a88..6dee6f77ec 100644 --- a/applications/Unity.GrantManager/.github/agents/pre-readiness-deep.agent.md +++ b/applications/Unity.GrantManager/.github/agents/pre-readiness-deep.agent.md @@ -34,7 +34,7 @@ For each changed file in the PR: ### Step 3: ABP Architecture - Layer boundaries (Domain → Application → Web) -- Repository/DTO/AutoMapper conventions +- Repository/DTO/Mapperly conventions - Permissions and localization keys - EF migrations (if schema changes) @@ -131,7 +131,7 @@ When invoked: - ✅ Build/tests pass (backend unit tests) - ✅ **Cypress E2E tests pass** (frontend integration tests) - ✅ ABP conventions followed -- ✅ AutoMapper/localization/permissions configured +- ✅ Mapperly/localization/permissions configured ## Tool Usage diff --git a/applications/Unity.GrantManager/.github/agents/unity-abp-instructions.md b/applications/Unity.GrantManager/.github/agents/unity-abp-instructions.md index 573577e9a5..45202706b7 100644 --- a/applications/Unity.GrantManager/.github/agents/unity-abp-instructions.md +++ b/applications/Unity.GrantManager/.github/agents/unity-abp-instructions.md @@ -245,7 +245,7 @@ formatter.format(amount); // Returns formatted currency string 3. Create migration 4. Create DTOs in `*.Application.Contracts` 5. Create application service in `*.Application` -6. Add AutoMapper mappings +6. Add Mapperly mappings 7. Define permissions 8. Create MVC controller and views diff --git a/applications/Unity.GrantManager/.github/copilot-instructions.md b/applications/Unity.GrantManager/.github/copilot-instructions.md index b54ee4fc9b..07b31d892a 100644 --- a/applications/Unity.GrantManager/.github/copilot-instructions.md +++ b/applications/Unity.GrantManager/.github/copilot-instructions.md @@ -5,9 +5,9 @@ ## Project Overview -Unity Grant Manager is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 9.1.3** with **.NET 9.0**, targeting **PostgreSQL 17**. The UI uses **Razor Pages** with a custom ABP theme (Unity.Theme.UX2). The architecture follows ABP's **Domain-Driven Design (DDD)** layered module pattern. +Unity Grant Manager is a **grant management portal** for the Province of British Columbia, built on **ABP Framework 10.3** with **.NET 10.0**, targeting **PostgreSQL 17**. The UI uses **Razor Pages** with a custom ABP theme (Unity.Theme.UX2). The architecture follows ABP's **Domain-Driven Design (DDD)** layered module pattern. -**Key stack:** .NET 9 · ABP 9.1.3 · EF Core 9.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · AutoMapper · Cypress (E2E) +**Key stack:** .NET 10 · ABP 10.3 · EF Core 10.0 · PostgreSQL 17 · Redis · RabbitMQ · xUnit · Shouldly · NSubstitute · Mapperly · Cypress (E2E) ## Repository Layout @@ -20,7 +20,7 @@ NuGet.Config ← NuGet package sources docker-compose.yml ← Docker dev environment src/ Unity.GrantManager.Web/ ← Razor Pages web app (entry point) - Unity.GrantManager.Application/ ← App services, AutoMapper profiles + Unity.GrantManager.Application/ ← App services, Mapperly mappers Unity.GrantManager.Application.Contracts/ ← DTOs, interfaces Unity.GrantManager.Domain/ ← Entities, repositories, domain services Unity.GrantManager.Domain.Shared/ ← Enums, constants, localization (en.json) @@ -93,7 +93,7 @@ Every PR triggers branch-specific GitHub Actions workflows (in the repo root `.g 1. **Validate source branch** — PRs to `dev` must come from `feature/*`, `hotfix/*`, `bugfix/*`, `test`, or `main`. PRs to `main` must come from `test` or `hotfix/*` only. 2. **Discover test projects** — Finds all `*Tests.csproj` files automatically. -3. **Run tests in parallel matrix** — Each test project runs independently with `dotnet test` using .NET 9.0.x. +3. **Run tests in parallel matrix** — Each test project runs independently with `dotnet test` using .NET 10.0.x. 4. **Aggregate results** — Posts pass/fail badge as PR comment. Always ensure `dotnet build` and `dotnet test` pass before submitting changes. @@ -135,8 +135,8 @@ Preferred code-usage boundaries (guidance for new code): - All methods `async`, end with `Async`. - Accept/return **DTOs only**, never entities. Define DTOs in `*.Application.Contracts`. - Make all public methods `virtual` for extensibility. -- This project uses **AutoMapper** (not Mapperly). Mapping profiles are `*AutoMapperProfile.cs` inheriting `Profile`. -- `ObjectMapper.Map<>()` is used for DTO mapping, not Mapperly partials. +- This project uses **Mapperly** (not AutoMapper). Mapper classes are `*MapperlyProfile.cs` decorated with `[Mapper]` and inheriting `MapperBase` or `TwoWayMapperBase`. +- `ObjectMapper.Map<>()` is used for DTO mapping at call sites; Mapperly generates the implementation via source generation. ### EF Core @@ -178,7 +178,7 @@ Use the ABP workflow agents in `.github/agents/` to accelerate planning, develop - `feature-planner`: Convert a feature request or bug into a layered ABP implementation plan. - `ddd-modeler`: Design or review aggregates, invariants, repositories, and domain managers. -- `application-service-designer`: Define app service contracts, DTOs, authorization, and AutoMapper changes. +- `application-service-designer`: Define app service contracts, DTOs, authorization, and Mapperly mapper changes. - `efcore-migration-planner`: Plan host vs tenant EF Core model updates and migration steps safely. - `permissions-localization-auditor`: Audit diffs for permission coverage, localization keys, and hardcoded text. - `test-strategy`: Build risk-based unit/integration test plans for ABP features. diff --git a/applications/Unity.GrantManager/.github/instructions/csharp.instructions.md b/applications/Unity.GrantManager/.github/instructions/csharp.instructions.md index aa9978fb26..ba6334f86f 100644 --- a/applications/Unity.GrantManager/.github/instructions/csharp.instructions.md +++ b/applications/Unity.GrantManager/.github/instructions/csharp.instructions.md @@ -29,7 +29,7 @@ These properties are pre-injected in `ApplicationService`, `DomainService`, and | `CurrentUser` | Access authenticated user (Id, Name, Email, Roles) | | `CurrentTenant` | Access current tenant context (Id, Name) | | `L` / `L["Key"]` | Localization shortcut | -| `ObjectMapper` | AutoMapper-based mapping | +| `ObjectMapper` | Mapperly-based mapping | | `Logger` | Structured logging via `ILogger` | | `AuthorizationService` | Programmatic authorization checks | | `UnitOfWorkManager` | Manual unit-of-work control | @@ -57,8 +57,8 @@ These properties are pre-injected in `ApplicationService`, `DomainService`, and - All methods `async`, name ends with `Async`. - Accept/return DTOs only, never entities. Define DTOs in `*.Application.Contracts`. - Make all public methods `virtual`. -- Use **AutoMapper** (`ObjectMapper.Map<>()`) for DTO mapping. Do NOT use Mapperly. -- Mapping profiles: `*AutoMapperProfile.cs` inheriting `Profile`. +- Use **Mapperly** (`ObjectMapper.Map<>()`) for DTO mapping. Do NOT use AutoMapper. +- Mapper classes: `*MapperlyProfile.cs` decorated with `[Mapper]`, inheriting `MapperBase` or `TwoWayMapperBase`. ## Code Style @@ -85,8 +85,8 @@ These properties are pre-injected in `ApplicationService`, `DomainService`, and ## DTOs vs Entities - Application services MUST accept and return DTOs only, never entities -- Use `ObjectMapper` (AutoMapper) to map between entities and DTOs -- Define mapping profiles in `*AutoMapperProfile` class in Application project +- Use `ObjectMapper` (Mapperly) to map between entities and DTOs +- Define mappers in `*MapperlyProfile` class in Application project ## Authorization diff --git a/applications/Unity.GrantManager/.github/skills/unity-application-layer/SKILL.md b/applications/Unity.GrantManager/.github/skills/unity-application-layer/SKILL.md index f68910980b..cc0c200969 100644 --- a/applications/Unity.GrantManager/.github/skills/unity-application-layer/SKILL.md +++ b/applications/Unity.GrantManager/.github/skills/unity-application-layer/SKILL.md @@ -47,24 +47,35 @@ public interface IGrantAppService : IApplicationService - Do NOT use web types (`IFormFile`, `Stream`) — accept `byte[]` from controllers. - Do NOT call other app services in the same module. Use domain services or repositories. -## Object Mapping (AutoMapper) +## Object Mapping (Mapperly) -This project uses **AutoMapper** (not Mapperly). Mapping profiles are defined as: +This project uses **Mapperly** (not AutoMapper). Mapper classes are defined using `Riok.Mapperly.Abstractions` and `Volo.Abp.Mapperly`: ```csharp -public class GrantManagerApplicationAutoMapperProfile : Profile +using Riok.Mapperly.Abstractions; +using Volo.Abp.Mapperly; + +[Mapper] +public partial class GrantToGrantDtoMapper : MapperBase +{ + public override partial GrantDto Map(Grant source); + public override partial void Map(Grant source, GrantDto destination); +} + +// For bidirectional mapping: +[Mapper] +public partial class ZoneGroupDefinitionMapper : TwoWayMapperBase { - public GrantManagerApplicationAutoMapperProfile() - { - CreateMap(); - CreateMap(); - } + public override partial ZoneGroupDefinitionDto Map(ZoneGroupDefinition source); + public override partial void Map(ZoneGroupDefinition source, ZoneGroupDefinitionDto destination); + public override partial ZoneGroupDefinition ReverseMap(ZoneGroupDefinitionDto source); + public override partial void ReverseMap(ZoneGroupDefinitionDto source, ZoneGroupDefinition destination); } ``` -- Profile files follow `*AutoMapperProfile.cs` naming. -- Each Application and Web project has its own profile. -- Use `ObjectMapper.Map(source)` in app services. +- Mapper files follow `*MapperlyProfile.cs` naming; each Application and Web project has its own file. +- Use `[MapperIgnoreTarget(nameof(...))]` to skip properties, `[MapProperty]` to rename, and `[MapPropertyFromSource]` for custom resolver methods. +- Call sites still use `ObjectMapper.Map(source)` — Mapperly provides the source-generated implementation. ## Error Handling diff --git a/applications/Unity.GrantManager/.github/skills/unity-module-structure/SKILL.md b/applications/Unity.GrantManager/.github/skills/unity-module-structure/SKILL.md index 68ed0f8091..c26502645d 100644 --- a/applications/Unity.GrantManager/.github/skills/unity-module-structure/SKILL.md +++ b/applications/Unity.GrantManager/.github/skills/unity-module-structure/SKILL.md @@ -15,7 +15,7 @@ Unity.{ModuleName}/ Unity.{ModuleName}.Domain.Shared/ ← Enums, constants, localization, ETOs Unity.{ModuleName}.Domain/ ← Entities, repository interfaces, domain services Unity.{ModuleName}.Application.Contracts/ ← DTOs, app service interfaces - Unity.{ModuleName}.Application/ ← App service implementations, AutoMapper profiles + Unity.{ModuleName}.Application/ ← App service implementations, Mapperly mappers Unity.{ModuleName}.EntityFrameworkCore/ ← DbContext, migrations (if module has own DB tables) Unity.{ModuleName}.HttpApi/ ← REST controllers Unity.{ModuleName}.HttpApi.Client/ ← Remote client proxies diff --git a/applications/Unity.GrantManager/Directory.Build.props b/applications/Unity.GrantManager/Directory.Build.props index 87aa7c3ae2..4239024ce7 100644 --- a/applications/Unity.GrantManager/Directory.Build.props +++ b/applications/Unity.GrantManager/Directory.Build.props @@ -2,7 +2,7 @@ - + $(NoWarn);NU1701;MSB3277 @@ -10,7 +10,7 @@ - + diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Unity.AI.Application.Contracts.csproj b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Unity.AI.Application.Contracts.csproj index a78c926a82..d086c0cf1d 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Unity.AI.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application.Contracts/Unity.AI.Application.Contracts.csproj @@ -1,16 +1,15 @@ - net9.0 + net10.0 enable Unity.AI - - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionMode.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionMode.cs new file mode 100644 index 0000000000..5400a57a5c --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionMode.cs @@ -0,0 +1,17 @@ +namespace Unity.AI.Operations; + +/// +/// Execution strategy for multi-step AI flows that iterate over many work items +/// (e.g. multiple attachments, multiple scoresheet sections). +/// +public enum AIExecutionMode +{ + /// One item at a time, in order. Default; preserves legacy behavior. + Sequential, + + /// All items started concurrently and awaited together. + Parallel, + + /// All items sent through one batch operation. + Batch +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionModeResolver.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionModeResolver.cs new file mode 100644 index 0000000000..90ce666fa8 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionModeResolver.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.Configuration; +using Unity.AI.Prompts; +using Volo.Abp.DependencyInjection; + +namespace Unity.AI.Operations; + +/// +/// Resolves the configured for an AI operation. +/// Configuration keys (all optional, default = Sequential): +/// Azure:Operations:{operationName}:ExecutionMode - "Sequential" | "Parallel" | "Batch" (case-insensitive) +/// Azure:Operations:Defaults:ExecutionMode - default when operation override is absent +/// +public class AIExecutionModeResolver(IConfiguration configuration) : ITransientDependency +{ + public const string AttachmentSummaryOperation = AIPromptTypes.AttachmentSummary; + public const string ApplicationScoringOperation = AIPromptTypes.ApplicationScoring; + + public AIExecutionMode ResolveMode(string operationName) + { + var configured = configuration[$"Azure:Operations:{operationName}:ExecutionMode"]; + if (string.IsNullOrWhiteSpace(configured)) + { + configured = configuration["Azure:Operations:Defaults:ExecutionMode"]; + } + + return configured?.Trim().ToLowerInvariant() switch + { + "parallel" => AIExecutionMode.Parallel, + "batch" => AIExecutionMode.Batch, + _ => AIExecutionMode.Sequential + }; + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionStrategy.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionStrategy.cs new file mode 100644 index 0000000000..96078d8970 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AIExecutionStrategy.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Unity.AI.Operations; + +/// +/// Runs an async operation across a collection of items using a configurable execution mode. +/// Stateless and intentionally tiny: callers resolve mode and provide item/batch work. +/// +public static class AIExecutionStrategy +{ + public static async Task> RunAsync( + IReadOnlyCollection items, + AIExecutionMode mode, + Func> operation, + Func, Task>> batchOperation) + { + ArgumentNullException.ThrowIfNull(items); + ArgumentNullException.ThrowIfNull(operation); + ArgumentNullException.ThrowIfNull(batchOperation); + + if (items.Count == 0) + { + return []; + } + + switch (mode) + { + case AIExecutionMode.Parallel: + return [.. await Task.WhenAll(items.Select(operation))]; + + case AIExecutionMode.Batch: + return await batchOperation(items); + + default: + var sequential = new List(items.Count); + foreach (var item in items) + { + sequential.Add(await operation(item)); + } + return sequential; + } + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/ApplicationScoringService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/ApplicationScoringService.cs index bcbf240301..b030aad9c8 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/ApplicationScoringService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/ApplicationScoringService.cs @@ -21,6 +21,7 @@ public class ApplicationScoringService( IApplicationChefsFileAttachmentRepository applicationChefsFileAttachmentRepository, IScoresheetRepository scoresheetRepository, IAIService aiService, + AIExecutionModeResolver executionModeResolver, ILogger logger) : IApplicationScoringService, ITransientDependency { private readonly JsonSerializerOptions _jsonOptions = new() @@ -63,49 +64,21 @@ public async Task RegenerateAndSaveAsync(Guid applicationId, string? pro var formSchema = await GetFormSchemaAsync(formSubmission?.ApplicationFormVersionId); var promptData = PromptDataPayloadBuilder.BuildPromptDataPayload(application, formSubmission, formSchema, logger); + var sections = scoresheet.Sections.OrderBy(s => s.Order).ToList(); + var mode = executionModeResolver.ResolveMode(AIExecutionModeResolver.ApplicationScoringOperation); + + var perSectionResults = await AIExecutionStrategy.RunAsync( + sections, + mode, + section => ProcessSectionAsync(applicationId, section, promptData, attachmentSummaries, promptVersion), + batch => ProcessSectionsAsync(applicationId, batch, promptData, attachmentSummaries, promptVersion)); + var allSectionResults = new Dictionary(); - foreach (var section in scoresheet.Sections.OrderBy(s => s.Order)) + foreach (var sectionResult in perSectionResults) { - try - { - var sectionQuestionsData = new List(); - foreach (var field in section.Fields.OrderBy(f => f.Order)) - { - var options = ExtractSelectListOptions(field); - sectionQuestionsData.Add(new - { - id = field.Id.ToString(), - question = field.Label, - description = field.Description, - type = field.Type.ToString(), - options, - allowed_answers = ExtractSelectListOptionNumbers(options) - }); - } - - var applicationScoringRequest = new ApplicationScoringRequest - { - Data = promptData, - Attachments = attachmentSummaries, - SectionName = section.Name, - SectionSchema = JsonSerializer.SerializeToElement(sectionQuestionsData, _jsonOptions), - PromptVersion = promptVersion, - }; - var applicationScoringResponse = await aiService.GenerateApplicationScoringAsync(applicationScoringRequest); - - if (applicationScoringResponse.Answers.Count > 0) - { - var sectionJson = JsonSerializer.Serialize(applicationScoringResponse.Answers, _jsonOptions); - using var sectionDoc = JsonDocument.Parse(sectionJson); - foreach (var property in sectionDoc.RootElement.EnumerateObject()) - { - allSectionResults[property.Name] = property.Value.Clone(); - } - } - } - catch (Exception ex) + foreach (var kvp in sectionResult) { - logger.LogError(ex, "Error processing AI application scoring section {SectionName} for application {ApplicationId}", section.Name, applicationId); + allSectionResults[kvp.Key] = kvp.Value; } } @@ -116,6 +89,107 @@ public async Task RegenerateAndSaveAsync(Guid applicationId, string? pro return validatedJson; } + private async Task> ProcessSectionAsync( + Guid applicationId, + ScoresheetSection section, + JsonElement promptData, + List attachmentSummaries, + string? promptVersion) + { + var sectionResults = new Dictionary(); + try + { + var applicationScoringRequest = new ApplicationScoringRequest + { + Data = promptData, + Attachments = attachmentSummaries, + SectionName = section.Name, + SectionSchema = JsonSerializer.SerializeToElement(BuildSectionQuestionsData(section), _jsonOptions), + PromptVersion = promptVersion, + }; + var applicationScoringResponse = await aiService.GenerateApplicationScoringAsync(applicationScoringRequest); + + if (applicationScoringResponse.Answers.Count > 0) + { + CopyAnswers(applicationScoringResponse.Answers, sectionResults); + } + } + catch (Exception ex) + { + logger.LogError(ex, "Error processing AI application scoring section {SectionName} for application {ApplicationId}", section.Name, applicationId); + } + return sectionResults; + } + + private async Task>> ProcessSectionsAsync( + Guid applicationId, + IReadOnlyCollection sections, + JsonElement promptData, + List attachmentSummaries, + string? promptVersion) + { + var sectionResults = new Dictionary(); + try + { + var questions = sections + .OrderBy(s => s.Order) + .SelectMany(BuildSectionQuestionsData) + .ToList(); + + var applicationScoringRequest = new ApplicationScoringRequest + { + Data = promptData, + Attachments = attachmentSummaries, + SectionName = "All Sections", + SectionSchema = JsonSerializer.SerializeToElement(questions, _jsonOptions), + PromptVersion = promptVersion, + }; + var applicationScoringResponse = await aiService.GenerateApplicationScoringAsync(applicationScoringRequest); + + if (applicationScoringResponse.Answers.Count > 0) + { + CopyAnswers(applicationScoringResponse.Answers, sectionResults); + } + } + catch (Exception ex) + { + logger.LogError(ex, "Error processing AI application scoring batch for application {ApplicationId}", applicationId); + } + + return [sectionResults]; + } + + private static List BuildSectionQuestionsData(ScoresheetSection section) + { + var sectionQuestionsData = new List(); + foreach (var field in section.Fields.OrderBy(f => f.Order)) + { + var options = ExtractSelectListOptions(field); + sectionQuestionsData.Add(new + { + id = field.Id.ToString(), + section = section.Name, + question = field.Label, + description = field.Description, + type = field.Type.ToString(), + options, + allowed_answers = ExtractSelectListOptionNumbers(options) + }); + } + + return sectionQuestionsData; + } + + private void CopyAnswers(Dictionary answers, Dictionary results) + { + var answersJson = JsonSerializer.Serialize(answers, _jsonOptions); + using var answersDoc = JsonDocument.Parse(answersJson); + foreach (var property in answersDoc.RootElement.EnumerateObject()) + { + results[property.Name] = property.Value.Clone(); + } + } + private async Task GetFormSchemaAsync(Guid? formVersionId) { if (formVersionId == null) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AttachmentSummaryService.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AttachmentSummaryService.cs index b103aedb73..073b66d864 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AttachmentSummaryService.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AI/Operations/AttachmentSummaryService.cs @@ -16,6 +16,7 @@ public class AttachmentSummaryService( IChefsFileAttachmentStreamProvider chefsFileAttachmentStreamProvider, ITextExtractionService textExtractionService, IAIService aiService, + AIExecutionModeResolver executionModeResolver, ILogger logger) : IAttachmentSummaryService, ITransientDependency { private const string SummaryGenerationFailedMessage = "AI summary generation failed."; @@ -44,24 +45,47 @@ public async Task GenerateAndSaveAsync(Guid attachmentId, string? prompt public async Task> GenerateAndSaveAsync(IEnumerable attachmentIds, string? promptVersion = null) { - var summaries = new List(); + var ids = attachmentIds as IReadOnlyCollection ?? attachmentIds.ToList(); + var mode = executionModeResolver.ResolveMode(AIExecutionModeResolver.AttachmentSummaryOperation); + if (mode != AIExecutionMode.Sequential) + { + logger.LogWarning( + "AI attachment summary {ExecutionMode} mode is not supported by the current repository-backed execution path. Falling back to sequential execution.", + mode); + mode = AIExecutionMode.Sequential; + } + + return await AIExecutionStrategy.RunAsync( + ids, + mode, + id => GenerateOrFallbackAsync(id, promptVersion), + batch => GenerateSequentiallyAsync(batch, promptVersion)); + } + private async Task> GenerateSequentiallyAsync(IReadOnlyCollection attachmentIds, string? promptVersion) + { + var summaries = new List(attachmentIds.Count); foreach (var attachmentId in attachmentIds) { - try - { - summaries.Add(await GenerateAndSaveAsync(attachmentId, promptVersion)); - } - catch (Exception ex) - { - logger.LogError(ex, "Error generating AI summary for attachment {AttachmentId}", attachmentId); - summaries.Add(SummaryGenerationFailedMessage); - } + summaries.Add(await GenerateOrFallbackAsync(attachmentId, promptVersion)); } return summaries; } + private async Task GenerateOrFallbackAsync(Guid attachmentId, string? promptVersion) + { + try + { + return await GenerateAndSaveAsync(attachmentId, promptVersion); + } + catch (Exception ex) + { + logger.LogError(ex, "Error generating AI summary for attachment {AttachmentId}", attachmentId); + return SummaryGenerationFailedMessage; + } + } + public async Task> GenerateForApplicationAsync(Guid applicationId, string? promptVersion = null) { var attachmentIds = (await applicationChefsFileAttachmentRepository.GetListAsync(a => a.ApplicationId == applicationId)) diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationAutoMapperProfile.cs deleted file mode 100644 index 382fcee837..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationAutoMapperProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using Unity.AI.Domain; -using Unity.AI.Prompts; - -namespace Unity.AI; - -public class AIApplicationAutoMapperProfile : Profile -{ - public AIApplicationAutoMapperProfile() - { - CreateMap(); - CreateMap(MemberList.None); - - CreateMap(); - CreateMap(MemberList.None); - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs new file mode 100644 index 0000000000..092ea879d1 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationMapperlyProfile.cs @@ -0,0 +1,75 @@ +using System.Runtime.CompilerServices; +using Riok.Mapperly.Abstractions; +using Unity.AI.Domain; +using Unity.AI.Prompts; +using Volo.Abp.Mapperly; + +namespace Unity.AI; + +[Mapper] +public partial class AIPromptToAIPromptDtoMapper : MapperBase +{ + public override partial AIPromptDto Map(AIPrompt source); + + public override partial void Map(AIPrompt source, AIPromptDto destination); +} + +[Mapper] +public partial class CreateUpdateAIPromptDtoToAIPromptMapper : MapperBase +{ + [ObjectFactory] + private static AIPrompt CreateAIPrompt() => + (AIPrompt)RuntimeHelpers.GetUninitializedObject(typeof(AIPrompt)); + + [MapperIgnoreTarget(nameof(AIPrompt.Versions))] + [MapperIgnoreTarget(nameof(AIPrompt.TenantId))] + [MapperIgnoreTarget(nameof(AIPrompt.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(AIPrompt.CreationTime))] + [MapperIgnoreTarget(nameof(AIPrompt.CreatorId))] + [MapperIgnoreTarget(nameof(AIPrompt.LastModificationTime))] + [MapperIgnoreTarget(nameof(AIPrompt.LastModifierId))] + public override partial AIPrompt Map(CreateUpdateAIPromptDto source); + + [MapperIgnoreTarget(nameof(AIPrompt.Versions))] + [MapperIgnoreTarget(nameof(AIPrompt.TenantId))] + [MapperIgnoreTarget(nameof(AIPrompt.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(AIPrompt.CreationTime))] + [MapperIgnoreTarget(nameof(AIPrompt.CreatorId))] + [MapperIgnoreTarget(nameof(AIPrompt.LastModificationTime))] + [MapperIgnoreTarget(nameof(AIPrompt.LastModifierId))] + public override partial void Map(CreateUpdateAIPromptDto source, AIPrompt destination); +} + +[Mapper] +public partial class AIPromptVersionToAIPromptVersionDtoMapper : MapperBase +{ + public override partial AIPromptVersionDto Map(AIPromptVersion source); + + public override partial void Map(AIPromptVersion source, AIPromptVersionDto destination); +} + +[Mapper] +public partial class CreateUpdateAIPromptVersionDtoToAIPromptVersionMapper : MapperBase +{ + [ObjectFactory] + private static AIPromptVersion CreateAIPromptVersion() => + (AIPromptVersion)RuntimeHelpers.GetUninitializedObject(typeof(AIPromptVersion)); + + [MapperIgnoreTarget(nameof(AIPromptVersion.Prompt))] + [MapperIgnoreTarget(nameof(AIPromptVersion.TenantId))] + [MapperIgnoreTarget(nameof(AIPromptVersion.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(AIPromptVersion.CreationTime))] + [MapperIgnoreTarget(nameof(AIPromptVersion.CreatorId))] + [MapperIgnoreTarget(nameof(AIPromptVersion.LastModificationTime))] + [MapperIgnoreTarget(nameof(AIPromptVersion.LastModifierId))] + public override partial AIPromptVersion Map(CreateUpdateAIPromptVersionDto source); + + [MapperIgnoreTarget(nameof(AIPromptVersion.Prompt))] + [MapperIgnoreTarget(nameof(AIPromptVersion.TenantId))] + [MapperIgnoreTarget(nameof(AIPromptVersion.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(AIPromptVersion.CreationTime))] + [MapperIgnoreTarget(nameof(AIPromptVersion.CreatorId))] + [MapperIgnoreTarget(nameof(AIPromptVersion.LastModificationTime))] + [MapperIgnoreTarget(nameof(AIPromptVersion.LastModifierId))] + public override partial void Map(CreateUpdateAIPromptVersionDto source, AIPromptVersion destination); +} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationModule.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationModule.cs index 7acf7ae2e0..6030c31218 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/AIApplicationModule.cs @@ -3,7 +3,7 @@ using Unity.GrantManager; using Volo.Abp.Application; using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.TenantManagement; @@ -14,7 +14,7 @@ namespace Unity.AI; [DependsOn( typeof(AIApplicationContractsModule), typeof(AbpDddApplicationModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpTenantManagementDomainModule), typeof(FlexApplicationModule), typeof(GrantManagerDomainModule) @@ -41,11 +41,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); context.Services.AddHttpClientProxies( typeof(AIApplicationContractsModule).Assembly, diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Unity.AI.Application.csproj b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Unity.AI.Application.csproj index 7d4e3d6f08..4f55216397 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Unity.AI.Application.csproj +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Application/Unity.AI.Application.csproj @@ -1,22 +1,25 @@ - net9.0 + net10.0 enable Unity.AI - + - - - - - - - + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Unity.AI.Shared.csproj b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Unity.AI.Shared.csproj index 4cf3ed4e73..f094575dec 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Unity.AI.Shared.csproj +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Domain.Shared/Unity.AI.Shared.csproj @@ -3,19 +3,19 @@ - net9.0 + net10.0 enable Unity.AI true - - + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/AIWebAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/AIWebAutoMapperProfile.cs deleted file mode 100644 index 91e120f831..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/AIWebAutoMapperProfile.cs +++ /dev/null @@ -1,11 +0,0 @@ -using AutoMapper; - -namespace Unity.AI.Web; - -public class AIWebAutoMapperProfile : Profile -{ - public AIWebAutoMapperProfile() - { - // Define AutoMapper mappings for web layer here - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/AIWebModule.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/AIWebModule.cs index 26b64ccb61..424d468bd2 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/AIWebModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/AIWebModule.cs @@ -4,7 +4,7 @@ using Unity.AI.Web.Views.Settings; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.SettingManagement.Web; using Volo.Abp.SettingManagement.Web.Pages.SettingManagement; @@ -16,7 +16,7 @@ namespace Unity.AI.Web; [DependsOn( typeof(AIApplicationModule), typeof(AbpAspNetCoreMvcUiThemeSharedModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpSettingManagementWebModule) )] public class AIWebModule : AbpModule @@ -46,11 +46,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.MenuContributors.Add(new AIMenuContributor()); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); Configure(options => { diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/PromptTools/AIPromptToolAccessProvider.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/PromptTools/AIPromptToolAccessProvider.cs deleted file mode 100644 index 51d7221147..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/PromptTools/AIPromptToolAccessProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Configuration; -using System.Threading.Tasks; -using Unity.Modules.Shared.Permissions; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Security.Claims; - -namespace Unity.AI.Web.PromptTools; - -public class AIPromptToolAccessProvider( - IAuthorizationService authorizationService, - ICurrentPrincipalAccessor currentPrincipalAccessor, - IConfiguration configuration) : IAIPromptToolAccessProvider, ITransientDependency -{ - public async Task CanViewPromptToolsAsync() - { - var principal = currentPrincipalAccessor.Principal; - if (principal?.Identity?.IsAuthenticated != true) - { - return false; - } - - var authorizationResult = await authorizationService.AuthorizeAsync( - principal, - IdentityConsts.ITOperationsPolicyName); - - return authorizationResult.Succeeded; - } - - public string DefaultPromptVersion - { - get - { - var configuredPromptVersion = configuration["Azure:Operations:Defaults:PromptVersion"]; - if (string.IsNullOrWhiteSpace(configuredPromptVersion)) - { - configuredPromptVersion = configuration["Azure:OpenAI:PromptVersion"]; - } - - return string.IsNullOrWhiteSpace(configuredPromptVersion) - ? "v1" - : configuredPromptVersion.Trim().ToLowerInvariant(); - } - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/PromptTools/IAIPromptToolAccessProvider.cs b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/PromptTools/IAIPromptToolAccessProvider.cs deleted file mode 100644 index 80d0560ba7..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/PromptTools/IAIPromptToolAccessProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace Unity.AI.Web.PromptTools; - -public interface IAIPromptToolAccessProvider -{ - Task CanViewPromptToolsAsync(); - string DefaultPromptVersion { get; } -} diff --git a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Unity.AI.Web.csproj b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Unity.AI.Web.csproj index 40c586592c..b37df03bc2 100644 --- a/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Unity.AI.Web.csproj +++ b/applications/Unity.GrantManager/modules/Unity.AI/src/Unity.AI.Web/Unity.AI.Web.csproj @@ -3,7 +3,7 @@ - net9.0 + net10.0 enable true Library @@ -12,13 +12,16 @@ - - - + + + + + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/ScoresheetSectionDto.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/ScoresheetSectionDto.cs index 0568ad87bc..540bae64c2 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/ScoresheetSectionDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/ScoresheetSectionDto.cs @@ -8,9 +8,9 @@ namespace Unity.Flex.Scoresheets [Serializable] public class ScoresheetSectionDto : ExtensibleEntityDto { - public virtual string Name { get; private set; } = string.Empty; - public virtual uint Order { get; private set;} = 0; - public virtual Guid ScoresheetId { get; } - public virtual Collection Fields { get; private set; } = []; + public virtual string Name { get; set; } = string.Empty; + public virtual uint Order { get; set; } = 0; + public virtual Guid ScoresheetId { get; set; } + public virtual Collection Fields { get; set; } = []; } } diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Unity.Flex.Application.Contracts.csproj b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Unity.Flex.Application.Contracts.csproj index 351d88a80c..259d86d1c9 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Unity.Flex.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Unity.Flex.Application.Contracts.csproj @@ -1,22 +1,21 @@ - + - net9.0 + net10.0 enable Unity.Flex - - - - - - - - + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationAutoMapperProfile.cs deleted file mode 100644 index fbe39d8126..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationAutoMapperProfile.cs +++ /dev/null @@ -1,65 +0,0 @@ -using AutoMapper; -using System.Linq; -using System.Text.Json; -using Unity.Flex.Domain.ScoresheetInstances; -using Unity.Flex.Domain.Scoresheets; -using Unity.Flex.Domain.WorksheetInstances; -using Unity.Flex.Domain.WorksheetLinks; -using Unity.Flex.Domain.Worksheets; -using Unity.Flex.Scoresheets; -using Unity.Flex.WorksheetInstances; -using Unity.Flex.WorksheetLinks; -using Unity.Flex.Worksheets; - -namespace Unity.Flex; - -public class FlexApplicationAutoMapperProfile : Profile -{ - public FlexApplicationAutoMapperProfile() - { - CreateMap() - .ForMember(dest => dest.TotalSections, opt => opt.MapFrom(s => s.Sections.Select(s => s.Id).Count())) - .ForMember(dest => dest.TotalFields, opt => opt.MapFrom(s => s.Sections.SelectMany(s => s.Fields).Count())); - - CreateMap(); - CreateMap() - .ForMember(dest => dest.FieldWidth, opt => opt.MapFrom(src => - ParseFieldWidth(src.Definition))); - CreateMap(); - CreateMap().ReverseMap(); - CreateMap(); - - CreateMap() - .ForMember(dest => dest.TotalSections, opt => opt.MapFrom(s => s.Sections.Select(s => s.Id).Count())) - .ForMember(dest => dest.TotalFields, opt => opt.MapFrom(s => s.Sections.SelectMany(s => s.Fields).Count())); - - CreateMap(); - - CreateMap() - .ForMember(dest => dest.ExtraProperties, opt => opt.Ignore()) - .ForMember(dest => dest.Answer, opt => opt.Ignore()) - .ForMember(dest => dest.IsHumanConfirmed, opt => opt.Ignore()) - .ForMember(dest => dest.AICitation, opt => opt.Ignore()) - .ForMember(dest => dest.AIConfidence, opt => opt.Ignore()); - CreateMap() - .ForMember(dest => dest.Fields, opt => opt.MapFrom(src => src.Fields)) - .ForMember(dest => dest.ExtraProperties, opt => opt.Ignore()); - CreateMap() - .ForMember(dest => dest.Sections, opt => opt.MapFrom(src => src.Sections)); - CreateMap(); - CreateMap(); - } - - private static int? ParseFieldWidth(string? definition) - { - if (string.IsNullOrEmpty(definition)) return null; - try - { - using var doc = JsonDocument.Parse(definition); - if (doc.RootElement.TryGetProperty("fieldWidth", out var prop) && prop.TryGetInt32(out var value)) - return value > 0 ? value : null; - } - catch { /* malformed JSON — fall through */ } - return null; - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationMapperlyProfile.cs new file mode 100644 index 0000000000..9027e28a1b --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationMapperlyProfile.cs @@ -0,0 +1,225 @@ +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text.Json; +using Riok.Mapperly.Abstractions; +using Unity.Flex.Domain.ScoresheetInstances; +using Unity.Flex.Domain.Scoresheets; +using Unity.Flex.Domain.WorksheetInstances; +using Unity.Flex.Domain.WorksheetLinks; +using Unity.Flex.Domain.Worksheets; +using Unity.Flex.Scoresheets; +using Unity.Flex.WorksheetInstances; +using Unity.Flex.WorksheetLinks; +using Unity.Flex.Worksheets; +using Volo.Abp.Mapperly; + +namespace Unity.Flex; + +public class WorksheetToWorksheetDtoMapper : MapperBase +{ + public override WorksheetDto Map(Worksheet source) + { + var destination = new WorksheetDto(); + Map(source, destination); + return destination; + } + + public override void Map(Worksheet source, WorksheetDto destination) + { + destination.Id = source.Id; + destination.Name = source.Name; + destination.Title = source.Title; + destination.Version = source.Version; + destination.Published = source.Published; + destination.ReportViewName = source.ReportViewName; + destination.Sections = source.Sections? + .Select(s => new WorksheetSectionMapper().Map(s)) + .ToList() ?? []; + destination.TotalSections = (uint)(source.Sections?.Count ?? 0); + destination.TotalFields = (uint)(source.Sections?.SelectMany(s => s.Fields).Count() ?? 0); + } +} + +public class WorksheetToWorksheetBasicDtoMapper : MapperBase +{ + public override WorksheetBasicDto Map(Worksheet source) + { + var destination = new WorksheetBasicDto(); + Map(source, destination); + return destination; + } + + public override void Map(Worksheet source, WorksheetBasicDto destination) + { + destination.Id = source.Id; + destination.Name = source.Name; + destination.Title = source.Title; + destination.Version = source.Version; + destination.Published = source.Published; + destination.TotalSections = (uint)(source.Sections?.Count ?? 0); + destination.TotalFields = (uint)(source.Sections?.SelectMany(s => s.Fields).Count() ?? 0); + } +} + +[Mapper] +public partial class WorksheetLinkMapper : MapperBase +{ + public override partial WorksheetLinkDto Map(WorksheetLink source); + public override partial void Map(WorksheetLink source, WorksheetLinkDto destination); + + [MapperIgnoreTarget(nameof(WorksheetBasicDto.TotalFields))] + [MapperIgnoreTarget(nameof(WorksheetBasicDto.TotalSections))] + private partial WorksheetBasicDto MapWorksheetBasicDto(Worksheet source); +} + +[Mapper] +public partial class WorksheetSectionMapper : MapperBase +{ + public override WorksheetSectionDto Map(WorksheetSection source) + { + var destination = MapInternal(source); + destination.FieldWidth = ParseFieldWidth(source.Definition); + return destination; + } + + public override void Map(WorksheetSection source, WorksheetSectionDto destination) + { + MapInternal(source, destination); + destination.FieldWidth = ParseFieldWidth(source.Definition); + } + + [MapperIgnoreTarget(nameof(WorksheetSectionDto.FieldWidth))] + private partial WorksheetSectionDto MapInternal(WorksheetSection source); + + [MapperIgnoreTarget(nameof(WorksheetSectionDto.FieldWidth))] + private partial void MapInternal(WorksheetSection source, WorksheetSectionDto destination); + + private static int? ParseFieldWidth(string? definition) + { + if (string.IsNullOrEmpty(definition)) return null; + try + { + using var doc = JsonDocument.Parse(definition); + if (doc.RootElement.TryGetProperty("fieldWidth", out var prop) && prop.TryGetInt32(out var value)) + return value > 0 ? value : null; + } + catch (JsonException) { /* malformed JSON — fall through */ } + return null; + } +} + +[Mapper] +public partial class WorksheetInstanceMapper : MapperBase +{ + public override partial WorksheetInstanceDto Map(WorksheetInstance source); + public override partial void Map(WorksheetInstance source, WorksheetInstanceDto destination); +} + +[Mapper] +public partial class CustomFieldValueMapper : TwoWayMapperBase +{ + [ObjectFactory] + private static CustomFieldValue CreateCustomFieldValue() => + (CustomFieldValue)RuntimeHelpers.GetUninitializedObject(typeof(CustomFieldValue)); + + public override partial CustomFieldValueDto Map(CustomFieldValue source); + public override partial void Map(CustomFieldValue source, CustomFieldValueDto destination); + + // CustomFieldValue uses private setters on all business properties (DDD encapsulation); + // the reverse mapping is a no-op by design — only Id is copied via the factory object. +#pragma warning disable RMG066 + [MapperIgnoreTarget(nameof(CustomFieldValue.TenantId))] + [MapperIgnoreTarget(nameof(CustomFieldValue.LastModificationTime))] + [MapperIgnoreTarget(nameof(CustomFieldValue.LastModifierId))] + [MapperIgnoreTarget(nameof(CustomFieldValue.CreationTime))] + [MapperIgnoreTarget(nameof(CustomFieldValue.CreatorId))] + public override partial CustomFieldValue ReverseMap(CustomFieldValueDto source); + + [MapperIgnoreTarget(nameof(CustomFieldValue.TenantId))] + [MapperIgnoreTarget(nameof(CustomFieldValue.LastModificationTime))] + [MapperIgnoreTarget(nameof(CustomFieldValue.LastModifierId))] + [MapperIgnoreTarget(nameof(CustomFieldValue.CreationTime))] + [MapperIgnoreTarget(nameof(CustomFieldValue.CreatorId))] + public override partial void ReverseMap(CustomFieldValueDto source, CustomFieldValue destination); +#pragma warning restore RMG066 +} + +[Mapper] +public partial class CustomFieldMapper : MapperBase +{ + public override partial CustomFieldDto Map(CustomField source); + public override partial void Map(CustomField source, CustomFieldDto destination); +} + +[Mapper] +public partial class PersistWorksheetIntanceValuesMapper : MapperBase +{ + public override partial PersistWorksheetIntanceValuesEto Map(PersistWorksheetIntanceValuesDto source); + public override partial void Map(PersistWorksheetIntanceValuesDto source, PersistWorksheetIntanceValuesEto destination); +} + +[Mapper] +public partial class QuestionToQuestionDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(QuestionDto.ExtraProperties))] + [MapperIgnoreTarget(nameof(QuestionDto.Answer))] + [MapperIgnoreTarget(nameof(QuestionDto.IsHumanConfirmed))] + [MapperIgnoreTarget(nameof(QuestionDto.AICitation))] + [MapperIgnoreTarget(nameof(QuestionDto.AIConfidence))] + public override partial QuestionDto Map(Question source); + + [MapperIgnoreTarget(nameof(QuestionDto.ExtraProperties))] + [MapperIgnoreTarget(nameof(QuestionDto.Answer))] + [MapperIgnoreTarget(nameof(QuestionDto.IsHumanConfirmed))] + [MapperIgnoreTarget(nameof(QuestionDto.AICitation))] + [MapperIgnoreTarget(nameof(QuestionDto.AIConfidence))] + public override partial void Map(Question source, QuestionDto destination); +} + +[Mapper] +public partial class ScoresheetSectionMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ScoresheetSectionDto.ExtraProperties))] + public override partial ScoresheetSectionDto Map(ScoresheetSection source); + + [MapperIgnoreTarget(nameof(ScoresheetSectionDto.ExtraProperties))] + public override partial void Map(ScoresheetSection source, ScoresheetSectionDto destination); + + [MapperIgnoreTarget(nameof(QuestionDto.ExtraProperties))] + [MapperIgnoreTarget(nameof(QuestionDto.Answer))] + [MapperIgnoreTarget(nameof(QuestionDto.IsHumanConfirmed))] + [MapperIgnoreTarget(nameof(QuestionDto.AICitation))] + [MapperIgnoreTarget(nameof(QuestionDto.AIConfidence))] + private partial QuestionDto MapQuestion(Question source); +} + +[Mapper] +public partial class ScoresheetMapper : MapperBase +{ + public override partial ScoresheetDto Map(Scoresheet source); + public override partial void Map(Scoresheet source, ScoresheetDto destination); + + [MapperIgnoreTarget(nameof(ScoresheetSectionDto.ExtraProperties))] + private partial ScoresheetSectionDto MapSection(ScoresheetSection source); + + [MapperIgnoreTarget(nameof(QuestionDto.ExtraProperties))] + [MapperIgnoreTarget(nameof(QuestionDto.Answer))] + [MapperIgnoreTarget(nameof(QuestionDto.IsHumanConfirmed))] + [MapperIgnoreTarget(nameof(QuestionDto.AICitation))] + [MapperIgnoreTarget(nameof(QuestionDto.AIConfidence))] + private partial QuestionDto MapQuestion(Question source); +} + +[Mapper] +public partial class ScoresheetInstanceMapper : MapperBase +{ + public override partial ScoresheetInstanceDto Map(ScoresheetInstance source); + public override partial void Map(ScoresheetInstance source, ScoresheetInstanceDto destination); +} + +[Mapper] +public partial class AnswerMapper : MapperBase +{ + public override partial AnswerDto Map(Answer source); + public override partial void Map(Answer source, AnswerDto destination); +} diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationModule.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationModule.cs index 8e699230ab..c2f19c2cfd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/FlexApplicationModule.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.Application; using Volo.Abp.Domain; @@ -13,7 +13,7 @@ namespace Unity.Flex; [DependsOn( typeof(AbpDddApplicationModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpValidationModule), typeof(AbpDddDomainSharedModule), typeof(AbpVirtualFileSystemModule), @@ -41,11 +41,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); context.Services.AddHttpClientProxies( typeof(FlexApplicationContractsModule).Assembly, diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Unity.Flex.Application.csproj b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Unity.Flex.Application.csproj index 1e8cdf5394..331e21863e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Unity.Flex.Application.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application/Unity.Flex.Application.csproj @@ -1,25 +1,25 @@ - + - net9.0 + net10.0 enable Unity.Flex - - - - - - - - - - - + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Shared/Unity.Flex.Shared.csproj b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Shared/Unity.Flex.Shared.csproj index 732f5d9935..9963d2d2bd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Shared/Unity.Flex.Shared.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Shared/Unity.Flex.Shared.csproj @@ -1,25 +1,24 @@ - + - net9.0 + net10.0 enable Unity.Flex true - - + + - - - + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/FlexWebAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/FlexWebAutoMapperProfile.cs deleted file mode 100644 index a3c1899529..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/FlexWebAutoMapperProfile.cs +++ /dev/null @@ -1,13 +0,0 @@ -using AutoMapper; - -namespace Unity.Flex.Web; - -public class FlexWebAutoMapperProfile : Profile -{ - public FlexWebAutoMapperProfile() - { - /* You can configure your AutoMapper mapping configuration here. - * Alternatively, you can split your mapping configurations - * into multiple profile classes for a better organization. */ - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/FlexWebModule.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/FlexWebModule.cs index 2b8ccff96b..639b36feae 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/FlexWebModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/FlexWebModule.cs @@ -3,7 +3,7 @@ using Unity.Flex.Localization; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; @@ -12,7 +12,7 @@ namespace Unity.Flex.Web; [DependsOn( typeof(FlexApplicationContractsModule), typeof(AbpAspNetCoreMvcUiThemeSharedModule), - typeof(AbpAutoMapperModule) + typeof(AbpMapperlyModule) )] public class FlexWebModule : AbpModule { @@ -38,11 +38,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); Configure(options => { diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Unity.Flex.Web.csproj b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Unity.Flex.Web.csproj index ebac4ee989..349cb06a44 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Unity.Flex.Web.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Web/Unity.Flex.Web.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable true Library @@ -12,15 +12,13 @@ - - - - - + + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Application.Tests/Unity.Flex.Application.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Application.Tests/Unity.Flex.Application.Tests.csproj index b18cfc9584..b52b4f9eee 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Application.Tests/Unity.Flex.Application.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Application.Tests/Unity.Flex.Application.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.Flex @@ -11,14 +11,13 @@ - - - + + + - - - - + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.TestBase/Unity.Flex.TestBase.csproj b/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.TestBase/Unity.Flex.TestBase.csproj index ded6563714..bc1afd5896 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.TestBase/Unity.Flex.TestBase.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.TestBase/Unity.Flex.TestBase.csproj @@ -1,15 +1,15 @@ - + - net9.0 + net10.0 enable Unity.Flex - + @@ -17,18 +17,17 @@ runtime; build; native; contentfiles; analyzers - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Web.Tests/Unity.Flex.Web.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Web.Tests/Unity.Flex.Web.Tests.csproj index 397bb1b582..ce4d41158a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Web.Tests/Unity.Flex.Web.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Flex/test/Unity.Flex.Web.Tests/Unity.Flex.Web.Tests.csproj @@ -1,7 +1,7 @@ - + - net9.0 + net10.0 enable enable @@ -14,18 +14,20 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Pages/Identity/Users/EditModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Pages/Identity/Users/EditModal.cshtml.cs index eb9fd5b530..44815c039a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Pages/Identity/Users/EditModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Pages/Identity/Users/EditModal.cshtml.cs @@ -11,6 +11,7 @@ using Volo.Abp.Validation; using Volo.Abp; using Volo.Abp.Data; +using Unity.GrantManager.Identity; namespace Unity.Identity.Web.Pages.Identity.Users; @@ -25,15 +26,21 @@ public class EditModalModel : IdentityPageModel public DetailViewModel Detail { get; set; } protected IIdentityUserAppService IdentityUserAppService { get; } + protected IIdentityRoleAppService IdentityRoleAppService { get; } + protected IUserImportAppService UserImportAppService { get; } public bool IsEditCurrentUser { get; set; } private readonly IDataFilter _dataFilter; public EditModalModel(IIdentityUserAppService identityUserAppService, + IIdentityRoleAppService identityRoleAppService, + IUserImportAppService userImportAppService, IDataFilter dataFilter) { IdentityUserAppService = identityUserAppService; + IdentityRoleAppService = identityRoleAppService; + UserImportAppService = userImportAppService; _dataFilter = dataFilter; } @@ -41,7 +48,7 @@ public virtual async Task OnGetAsync(Guid id) { var user = await IdentityUserAppService.GetAsync(id); UserInfo = ObjectMapper.Map(user); - Roles = ObjectMapper.Map, AssignedRoleViewModel[]>((await IdentityUserAppService.GetAssignableRolesAsync()).Items); + Roles = ObjectMapper.Map, AssignedRoleViewModel[]>((await IdentityRoleAppService.GetAllListAsync()).Items); IsEditCurrentUser = CurrentUser.Id == id; var userRoleNames = (await IdentityUserAppService.GetRolesAsync(UserInfo.Id)).Items.Select(r => r.Name).ToList(); @@ -76,9 +83,8 @@ public virtual async Task OnPostAsync() { ValidateModel(); - var input = ObjectMapper.Map(UserInfo); - input.RoleNames = Roles.Where(r => r.IsAssigned).Select(r => r.Name).ToArray(); - await IdentityUserAppService.UpdateRolesAsync(UserInfo.Id, new IdentityUserUpdateRolesDto() { RoleNames = input.RoleNames }); + var roleNames = Roles.Where(r => r.IsAssigned).Select(r => r.Name).ToArray(); + await UserImportAppService.SetUserRolesAsync(UserInfo.Id, roleNames); return NoContent(); } diff --git a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Unity.Identity.Web.csproj b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Unity.Identity.Web.csproj index 67eb681207..ac7d62ebe2 100644 --- a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Unity.Identity.Web.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/Unity.Identity.Web.csproj @@ -1,7 +1,7 @@ - + latest - net9.0 + net10.0 Unity.Identity.Web Unity.Identity.Web false @@ -31,17 +31,17 @@ - - - - - - - + + + + + + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnityIdentityWebAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnityIdentityWebAutoMapperProfile.cs deleted file mode 100644 index eb8c208776..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnityIdentityWebAutoMapperProfile.cs +++ /dev/null @@ -1,49 +0,0 @@ -using AutoMapper; -using static Unity.Identity.Web.Pages.Identity.Users.EditModalModel; -using EditUserModalModel = Unity.Identity.Web.Pages.Identity.Users.EditModalModel; - -namespace Volo.Abp.Identity.Web; - -public class UnityIdentityWebAutoMapperProfile : Profile -{ - public UnityIdentityWebAutoMapperProfile() - { - CreateUserMappings(); - CreateRoleMappings(); - } - - protected void CreateUserMappings() - { - //EditModal - CreateMap() - .MapExtraProperties() - .ForMember(dest => dest.RoleNames, opt => opt.Ignore()) - .ForMember(dest => dest.PhoneNumber, opt => opt.Ignore()) - .ForMember(dest => dest.Password, opt => opt.Ignore()) - .ForMember(dest => dest.LockoutEnabled, opt => opt.Ignore()) - .ForMember(dest => dest.IsActive, opt => opt.Ignore()); - - CreateMap() - .ForMember(dest => dest.IsAssigned, opt => opt.Ignore()); - - CreateMap() - .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) - .ForMember(dest => dest.ModifiedBy, opt => opt.Ignore()); - - CreateMap(); - } - - protected void CreateRoleMappings() - { - //List - CreateMap(); - - //CreateModal - CreateMap() - .MapExtraProperties(); - - //EditModal - CreateMap() - .MapExtraProperties(); - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnityIdentityWebMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnityIdentityWebMapperlyProfile.cs new file mode 100644 index 0000000000..8eaea983a8 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnityIdentityWebMapperlyProfile.cs @@ -0,0 +1,126 @@ +using Riok.Mapperly.Abstractions; +using Unity.Identity.Web.Pages.Identity.Roles; +using Volo.Abp.Identity; +using Volo.Abp.Mapperly; +using static Unity.Identity.Web.Pages.Identity.Users.EditModalModel; +using EditRoleModal = Unity.Identity.Web.Pages.Identity.Roles.EditModalModel; +using CreateRoleModal = Unity.Identity.Web.Pages.Identity.Roles.CreateModalModel; + +namespace Volo.Abp.Identity.Web; + +internal static class IdentityExtraPropertiesCopier +{ + public static void Copy(Volo.Abp.Data.IHasExtraProperties source, Volo.Abp.Data.IHasExtraProperties destination) + { + foreach (var kvp in source.ExtraProperties) + { + destination.ExtraProperties[kvp.Key] = kvp.Value; + } + } +} + +[Mapper] +public partial class IdentityRoleDtoToAssignedRoleViewModelMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(AssignedRoleViewModel.IsAssigned))] + public override partial AssignedRoleViewModel Map(IdentityRoleDto source); + + [MapperIgnoreTarget(nameof(AssignedRoleViewModel.IsAssigned))] + public override partial void Map(IdentityRoleDto source, AssignedRoleViewModel destination); +} + +[Mapper] +public partial class IdentityUserDtoToDetailViewModelMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(DetailViewModel.CreatedBy))] + [MapperIgnoreTarget(nameof(DetailViewModel.ModifiedBy))] + public override partial DetailViewModel Map(IdentityUserDto source); + + [MapperIgnoreTarget(nameof(DetailViewModel.CreatedBy))] + [MapperIgnoreTarget(nameof(DetailViewModel.ModifiedBy))] + public override partial void Map(IdentityUserDto source, DetailViewModel destination); +} + +[Mapper] +public partial class IdentityUserDtoToUserInfoViewModelMapper : MapperBase +{ + public override partial UserInfoViewModel Map(IdentityUserDto source); + + public override partial void Map(IdentityUserDto source, UserInfoViewModel destination); +} + +[Mapper] +public partial class IdentityRoleDtoToEditRoleInfoMapper : MapperBase +{ + public override partial EditRoleModal.RoleInfoModel Map(IdentityRoleDto source); + + public override partial void Map(IdentityRoleDto source, EditRoleModal.RoleInfoModel destination); +} + +public class UserInfoViewModelToIdentityUserUpdateDtoMapper : MapperBase +{ + public override IdentityUserUpdateDto Map(UserInfoViewModel source) + { + var destination = new IdentityUserUpdateDto(); + Map(source, destination); + return destination; + } + + public override void Map(UserInfoViewModel source, IdentityUserUpdateDto destination) + { + destination.UserName = source.UserName; + destination.Name = source.Name; + destination.Surname = source.Surname; + destination.Email = source.Email; + destination.ConcurrencyStamp = source.ConcurrencyStamp; + IdentityExtraPropertiesCopier.Copy(source, destination); + } +} + +public class CreateRoleInfoToIdentityRoleCreateDtoMapper : MapperBase +{ + public override IdentityRoleCreateDto Map(CreateRoleModal.RoleInfoModel source) + { + var destination = new IdentityRoleCreateDto + { + Name = source.Name, + IsDefault = source.IsDefault, + IsPublic = source.IsPublic, + }; + IdentityExtraPropertiesCopier.Copy(source, destination); + return destination; + } + + public override void Map(CreateRoleModal.RoleInfoModel source, IdentityRoleCreateDto destination) + { + destination.Name = source.Name; + destination.IsDefault = source.IsDefault; + destination.IsPublic = source.IsPublic; + IdentityExtraPropertiesCopier.Copy(source, destination); + } +} + +public class EditRoleInfoToIdentityRoleUpdateDtoMapper : MapperBase +{ + public override IdentityRoleUpdateDto Map(EditRoleModal.RoleInfoModel source) + { + var destination = new IdentityRoleUpdateDto + { + Name = source.Name, + IsDefault = source.IsDefault, + IsPublic = source.IsPublic, + ConcurrencyStamp = source.ConcurrencyStamp, + }; + IdentityExtraPropertiesCopier.Copy(source, destination); + return destination; + } + + public override void Map(EditRoleModal.RoleInfoModel source, IdentityRoleUpdateDto destination) + { + destination.Name = source.Name; + destination.IsDefault = source.IsDefault; + destination.IsPublic = source.IsPublic; + destination.ConcurrencyStamp = source.ConcurrencyStamp; + IdentityExtraPropertiesCopier.Copy(source, destination); + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnitydentityWebModule.cs b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnitydentityWebModule.cs index 50d8dc7e18..6cbf5b921d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnitydentityWebModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Identity.Web/src/UnitydentityWebModule.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Http.ProxyScripting.Generators.JQuery; using Volo.Abp.Identity.Localization; using Volo.Abp.Localization; @@ -22,7 +22,7 @@ namespace Unity.Identity.Web; [DependsOn(typeof(AbpIdentityApplicationContractsModule))] -[DependsOn(typeof(AbpAutoMapperModule))] +[DependsOn(typeof(AbpMapperlyModule))] [DependsOn(typeof(AbpPermissionManagementWebModule))] [DependsOn(typeof(UnityAspNetCoreMvcUIThemeUX2Module))] public class UnitydentityWebModule : AbpModule @@ -54,12 +54,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - - Configure(options => - { - options.AddProfile(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); Configure(options => { diff --git a/applications/Unity.GrantManager/modules/Unity.Identity.Web/test/Unity.Identity.Web.Tests/Unity.Identity.Web.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Identity.Web/test/Unity.Identity.Web.Tests/Unity.Identity.Web.Tests.csproj index 3cbf5e2fa7..4f55729056 100644 --- a/applications/Unity.GrantManager/modules/Unity.Identity.Web/test/Unity.Identity.Web.Tests/Unity.Identity.Web.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Identity.Web/test/Unity.Identity.Web.Tests/Unity.Identity.Web.Tests.csproj @@ -1,7 +1,7 @@ - + - net9.0 + net10.0 enable enable diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Unity.Notifications.Application.Contracts.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Unity.Notifications.Application.Contracts.csproj index 2c56ca8d78..0a69ee557f 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Unity.Notifications.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Unity.Notifications.Application.Contracts.csproj @@ -1,20 +1,20 @@ - + - netstandard2.1;net9.0 + netstandard2.1;net10.0 enable Unity.Notifications - + - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs index 6a0172dd08..03793d3383 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs @@ -17,7 +17,7 @@ public class EmailAttachmentService : ITransientDependency { private const string S3BucketConfigKey = "S3:Bucket"; - private readonly AmazonS3Client _amazonS3Client; + private readonly IAmazonS3 _amazonS3Client; private readonly IEmailLogAttachmentRepository _emailLogAttachmentRepository; private readonly IConfiguration _configuration; private readonly ICurrentUser _currentUser; @@ -27,27 +27,14 @@ public EmailAttachmentService( IConfiguration configuration, IEmailLogAttachmentRepository emailLogAttachmentRepository, ICurrentUser currentUser, - ILogger logger) + ILogger logger, + IAmazonS3 amazonS3Client) { _configuration = configuration; _emailLogAttachmentRepository = emailLogAttachmentRepository; _currentUser = currentUser; _logger = logger; - - // Initialize S3 client (same pattern as S3BlobProvider) - var s3Config = new AmazonS3Config - { - RegionEndpoint = null, - ServiceURL = configuration["S3:Endpoint"], - AllowAutoRedirect = true, - ForcePathStyle = true - }; - - _amazonS3Client = new AmazonS3Client( - configuration["S3:AccessKeyId"], - configuration["S3:SecretAccessKey"], - s3Config - ); + _amazonS3Client = amazonS3Client; } public async Task UploadAttachmentAsync( diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationAutoMapperProfile.cs deleted file mode 100644 index e9ad095c58..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationAutoMapperProfile.cs +++ /dev/null @@ -1,18 +0,0 @@ -using AutoMapper; -using Unity.Notifications.EmailGroups; -using Unity.Notifications.Emails; -using Volo.Abp.Users; - -namespace Unity.Notifications; - -public class NotificationsApplicationAutoMapperProfile : Profile -{ - public NotificationsApplicationAutoMapperProfile() - { - CreateMap() - .ForMember(x => x.SentBy, map => map.Ignore()); - CreateMap(); - CreateMap(); - CreateMap(); - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationMapperlyProfile.cs new file mode 100644 index 0000000000..cb09db759b --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationMapperlyProfile.cs @@ -0,0 +1,47 @@ +using Riok.Mapperly.Abstractions; +using Unity.Notifications.EmailGroups; +using Unity.Notifications.Emails; +using Volo.Abp.Mapperly; +using Volo.Abp.Users; + +namespace Unity.Notifications; + +[Mapper] +public partial class EmailLogToEmailHistoryDtoMapper : MapperBase +{ + [MapProperty(nameof(EmailLog.CC), nameof(EmailHistoryDto.Cc))] + [MapProperty(nameof(EmailLog.BCC), nameof(EmailHistoryDto.Bcc))] + [MapperIgnoreTarget(nameof(EmailHistoryDto.SentBy))] + [MapperIgnoreTarget(nameof(EmailHistoryDto.ExtraProperties))] + public override partial EmailHistoryDto Map(EmailLog source); + + [MapProperty(nameof(EmailLog.CC), nameof(EmailHistoryDto.Cc))] + [MapProperty(nameof(EmailLog.BCC), nameof(EmailHistoryDto.Bcc))] + [MapperIgnoreTarget(nameof(EmailHistoryDto.SentBy))] + [MapperIgnoreTarget(nameof(EmailHistoryDto.ExtraProperties))] + public override partial void Map(EmailLog source, EmailHistoryDto destination); +} + +[Mapper] +public partial class IUserDataToEmailHistoryUserDtoMapper : MapperBase +{ + public override partial EmailHistoryUserDto Map(IUserData source); + + public override partial void Map(IUserData source, EmailHistoryUserDto destination); +} + +[Mapper] +public partial class EmailGroupToEmailGroupDtoMapper : MapperBase +{ + public override partial EmailGroupDto Map(EmailGroup source); + + public override partial void Map(EmailGroup source, EmailGroupDto destination); +} + +[Mapper] +public partial class EmailGroupUserToEmailGroupUsersDtoMapper : MapperBase +{ + public override partial EmailGroupUsersDto Map(EmailGroupUser source); + + public override partial void Map(EmailGroupUser source, EmailGroupUsersDto destination); +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationModule.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationModule.cs index 5cb5c5a912..828e253693 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationModule.cs @@ -1,5 +1,6 @@ +using Amazon.S3; using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.Application; using Volo.Abp.BackgroundJobs; @@ -11,6 +12,7 @@ using Volo.Abp.Application.Dtos; using Volo.Abp.Http.Client; using Unity.Modules.Shared.Http; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Unity.Notifications; @@ -18,7 +20,7 @@ namespace Unity.Notifications; typeof(NotificationsDomainModule), typeof(NotificationsApplicationContractsModule), typeof(AbpDddApplicationModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpBackgroundJobsModule), typeof(AbpBackgroundWorkersQuartzModule), typeof(AbpHttpClientModule) @@ -27,14 +29,24 @@ public class NotificationsApplicationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddAutoMapperObjectMapper(); - context.Services.AddTransient(); + var configuration = context.Services.GetConfiguration(); - Configure(options => + context.Services.TryAddSingleton(_ => { - options.AddMaps(validate: true); + var s3Config = new AmazonS3Config + { + RegionEndpoint = null, + ServiceURL = configuration["S3:Endpoint"], + AllowAutoRedirect = true, + ForcePathStyle = true + }; + return new AmazonS3Client(configuration["S3:AccessKeyId"], configuration["S3:SecretAccessKey"], s3Config); }); + context.Services.AddMapperlyObjectMapper(); + + context.Services.AddTransient(); + context.Services.AddHttpClientProxies( typeof(NotificationsApplicationContractsModule).Assembly, NotificationsRemoteServiceConsts.RemoteServiceName diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Unity.Notifications.Application.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Unity.Notifications.Application.csproj index 0cfa16c59c..ae66935375 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Unity.Notifications.Application.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Unity.Notifications.Application.csproj @@ -1,30 +1,29 @@ - + - net9.0 + net10.0 enable Unity.Notifications - + - - - + - - - - - - - - - - + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain.Shared/Unity.Notifications.Domain.Shared.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain.Shared/Unity.Notifications.Domain.Shared.csproj index 00b21bb756..2eb1af44f6 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain.Shared/Unity.Notifications.Domain.Shared.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain.Shared/Unity.Notifications.Domain.Shared.csproj @@ -1,23 +1,23 @@ - + - netstandard2.1;net9.0 + netstandard2.1;net10.0 enable Unity.Notifications true - - - - + + + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs index 58b935a77d..c47d8a0b06 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs @@ -23,28 +23,28 @@ public async Task SeedAsync(DataSeedContext context) var emailTemplateVariableDtos = new List { - new EmailTempateVariableDto { Name = "Applicant name", Token = "applicant_name", MapTo = "applicant.applicantName" }, - new EmailTempateVariableDto { Name = "Submission #", Token = "submission_number", MapTo = "referenceNo" }, - new EmailTempateVariableDto { Name = "Submission Date", Token = "submission_date", MapTo = "submissionDate" }, - new EmailTempateVariableDto { Name = "Category", Token = "category", MapTo = "applicationForm.category" }, - new EmailTempateVariableDto { Name = "Status", Token = "status", MapTo = "status" }, - new EmailTempateVariableDto { Name = "Approved Amount", Token = "approved_amount", MapTo = "approvedAmount" }, - new EmailTempateVariableDto { Name = "Approval date", Token = "approval_date", MapTo = "finalDecisionDate" }, - new EmailTempateVariableDto { Name = "Community", Token = "community", MapTo = "community" }, - new EmailTempateVariableDto { Name = "Contact Full Name", Token = "contact_full_name", MapTo = "contactFullName" }, - new EmailTempateVariableDto { Name = "Contact Title", Token = "contact_title", MapTo = "contactTitle" }, - new EmailTempateVariableDto { Name = "Decline Rationale", Token = "decline_rationale", MapTo = "declineRational" }, - new EmailTempateVariableDto { Name = "Registered Organization Name", Token = "organization_name", MapTo = "organizationName" }, - new EmailTempateVariableDto { Name = "Project Start Date", Token = "project_start_date", MapTo = "projectStartDate" }, - new EmailTempateVariableDto { Name = "Project End Date", Token = "project_end_date", MapTo = "projectEndDate" }, - new EmailTempateVariableDto { Name = "Project Name", Token = "project_name", MapTo = "projectName" }, - new EmailTempateVariableDto { Name = "Project Summary", Token = "project_summary", MapTo = "projectSummary" }, - new EmailTempateVariableDto { Name = "Signing Authority Full Name", Token = "signing_authority_full_name", MapTo = "signingAuthorityFullName" }, - new EmailTempateVariableDto { Name = "Signing Authority Title", Token = "signing_authority_title", MapTo = "signingAuthorityTitle" }, - new EmailTempateVariableDto { Name = "Applicant ID", Token = "applicant_id", MapTo = "applicant.unityApplicantId" }, - new EmailTempateVariableDto { Name = "Requested Amount", Token = "requested_amount", MapTo = "requestedAmount" }, - new EmailTempateVariableDto { Name = "Recommended Amount", Token = "recommended_amount", MapTo = "recommendedAmount" }, - new EmailTempateVariableDto { Name = "Unity Application ID", Token = "unity_application_id", MapTo = "unityApplicationId" } + new() { Name = "Applicant name", Token = "applicant_name", MapTo = "applicant.applicantName" }, + new() { Name = "Submission #", Token = "submission_number", MapTo = "referenceNo" }, + new() { Name = "Submission Date", Token = "submission_date", MapTo = "submissionDate" }, + new() { Name = "Category", Token = "category", MapTo = "applicationForm.category" }, + new() { Name = "Status", Token = "status", MapTo = "status" }, + new() { Name = "Approved Amount", Token = "approved_amount", MapTo = "approvedAmount" }, + new() { Name = "Approval date", Token = "approval_date", MapTo = "finalDecisionDate" }, + new() { Name = "Community", Token = "community", MapTo = "community" }, + new() { Name = "Contact Full Name", Token = "contact_full_name", MapTo = "contactFullName" }, + new() { Name = "Contact Title", Token = "contact_title", MapTo = "contactTitle" }, + new() { Name = "Decline Rationale", Token = "decline_rationale", MapTo = "declineRational" }, + new() { Name = "Registered Organization Name", Token = "organization_name", MapTo = "organizationName" }, + new() { Name = "Project Start Date", Token = "project_start_date", MapTo = "projectStartDate" }, + new() { Name = "Project End Date", Token = "project_end_date", MapTo = "projectEndDate" }, + new() { Name = "Project Name", Token = "project_name", MapTo = "projectName" }, + new() { Name = "Project Summary", Token = "project_summary", MapTo = "projectSummary" }, + new() { Name = "Signing Authority Full Name", Token = "signing_authority_full_name", MapTo = "signingAuthorityFullName" }, + new() { Name = "Signing Authority Title", Token = "signing_authority_title", MapTo = "signingAuthorityTitle" }, + new() { Name = "Applicant ID", Token = "applicant_id", MapTo = "applicant.unityApplicantId" }, + new() { Name = "Requested Amount", Token = "requested_amount", MapTo = "requestedAmount" }, + new() { Name = "Recommended Amount", Token = "recommended_amount", MapTo = "recommendedAmount" }, + new() { Name = "Unity Application ID", Token = "unity_application_id", MapTo = "unityApplicationId" } }; try @@ -74,8 +74,8 @@ await templateVariablesRepository.InsertAsync( var emailGroups = new List { - new EmailGroupDto {Name = "FSB-AP", Description = "This group manages the recipients for PO-related payments, which will be sent to FSB-AP to update contracts and initiate payment creation.",Type = "static"}, - new EmailGroupDto {Name = "Payments", Description = "This group manages the recipients for payment notifications, such as failures or errors",Type = "static"} + new() {Name = "FSB-AP", Description = "This group manages the recipients for PO-related payments, which will be sent to FSB-AP to update contracts and initiate payment creation.",Type = "static"}, + new() {Name = "Payments", Description = "This group manages the recipients for payment notifications, such as failures or errors",Type = "static"} }; try { diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/Unity.Notifications.Domain.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/Unity.Notifications.Domain.csproj index c93e37eeeb..a4cf76b437 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/Unity.Notifications.Domain.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/Unity.Notifications.Domain.csproj @@ -1,18 +1,18 @@ - + - netstandard2.1;net9.0 + netstandard2.1;net10.0 enable Unity.Notifications - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Unity.Notifications.EntityFrameworkCore.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Unity.Notifications.EntityFrameworkCore.csproj index 2581c28884..35443ef745 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Unity.Notifications.EntityFrameworkCore.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Unity.Notifications.EntityFrameworkCore.csproj @@ -1,19 +1,18 @@ - + - net9.0 + net10.0 enable Unity.Notifications - - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi.Client/Unity.Notifications.HttpApi.Client.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi.Client/Unity.Notifications.HttpApi.Client.csproj index 8c7583fc6d..451ddaea79 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi.Client/Unity.Notifications.HttpApi.Client.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi.Client/Unity.Notifications.HttpApi.Client.csproj @@ -1,17 +1,17 @@ - + - netstandard2.1;net9.0 + netstandard2.1;net10.0 enable Unity.Notifications - - - + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi/Unity.Notifications.HttpApi.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi/Unity.Notifications.HttpApi.csproj index fdf913f148..4c17656712 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi/Unity.Notifications.HttpApi.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.HttpApi/Unity.Notifications.HttpApi.csproj @@ -1,18 +1,17 @@ - + - net9.0 + net10.0 enable Unity.Notifications - - - - + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Installer/Unity.Notifications.Installer.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Installer/Unity.Notifications.Installer.csproj index 427d04a75b..a6e97532ec 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Installer/Unity.Notifications.Installer.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Installer/Unity.Notifications.Installer.csproj @@ -1,18 +1,17 @@ - + - net9.0 + net10.0 enable true Unity.Notifications - - - + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/NotificationsWebAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/NotificationsWebAutoMapperProfile.cs deleted file mode 100644 index f2f51fdfbc..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/NotificationsWebAutoMapperProfile.cs +++ /dev/null @@ -1,13 +0,0 @@ -using AutoMapper; - -namespace Unity.Notifications.Web; - -public class NotificationsWebAutoMapperProfile : Profile -{ - public NotificationsWebAutoMapperProfile() - { - /* You can configure your AutoMapper mapping configuration here. - * Alternatively, you can split your mapping configurations - * into multiple profile classes for a better organization. */ - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/NotificationsWebModule.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/NotificationsWebModule.cs index 72b2c3d0f1..556c6d76a1 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/NotificationsWebModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/NotificationsWebModule.cs @@ -7,7 +7,7 @@ using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.BackgroundJobs; using Volo.Abp.BackgroundWorkers.Quartz; using Volo.Abp.Modularity; @@ -22,7 +22,7 @@ namespace Unity.Notifications.Web; typeof(NotificationsApplicationModule), typeof(NotificationsApplicationContractsModule), typeof(AbpAspNetCoreMvcUiThemeSharedModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpSettingManagementWebModule) )] public class NotificationsWebModule : AbpModule @@ -69,16 +69,12 @@ public override void ConfigureServices(ServiceConfigurationContext context) }); Configure(options => - { - options.Contributors.Add(new NotificationsSettingPageContributor()); - }); - - context.Services.AddAutoMapperObjectMapper(); - Configure(options => { - options.AddMaps(validate: true); + options.Contributors.Add(new NotificationsSettingPageContributor()); }); + context.Services.AddMapperlyObjectMapper(); + Configure(options => { //Configure authorization. diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/Unity.Notifications.Web.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/Unity.Notifications.Web.csproj index 41857fff2f..3e110d2d7d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/Unity.Notifications.Web.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Web/Unity.Notifications.Web.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable true Library @@ -12,14 +12,15 @@ - - - - - - - - + + + + + + + + + @@ -28,7 +29,7 @@ - + @@ -48,10 +49,10 @@ - - - Always - + + + Always + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Application.Tests/Unity.Notifications.Application.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Application.Tests/Unity.Notifications.Application.Tests.csproj index d91ab66d90..94784c7e73 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Application.Tests/Unity.Notifications.Application.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Application.Tests/Unity.Notifications.Application.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.Notifications @@ -11,10 +11,11 @@ - - + + - + + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Domain.Tests/Unity.Notifications.Domain.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Domain.Tests/Unity.Notifications.Domain.Tests.csproj index 1aa14ca773..721959b2a2 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Domain.Tests/Unity.Notifications.Domain.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.Domain.Tests/Unity.Notifications.Domain.Tests.csproj @@ -1,19 +1,18 @@ - + - net9.0 + net10.0 enable Unity.Notifications - - - + + + - diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.EntityFrameworkCore.Tests/Unity.Notifications.EntityFrameworkCore.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.EntityFrameworkCore.Tests/Unity.Notifications.EntityFrameworkCore.Tests.csproj index eefeddd8e2..2e9f3f992b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.EntityFrameworkCore.Tests/Unity.Notifications.EntityFrameworkCore.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.EntityFrameworkCore.Tests/Unity.Notifications.EntityFrameworkCore.Tests.csproj @@ -1,23 +1,22 @@ - + - net9.0 + net10.0 enable Unity.Notifications - - - + + + - - + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.TestBase/Unity.Notifications.TestBase.csproj b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.TestBase/Unity.Notifications.TestBase.csproj index 32c3128e43..2969eb286a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.TestBase/Unity.Notifications.TestBase.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/test/Unity.Notifications.TestBase/Unity.Notifications.TestBase.csproj @@ -1,16 +1,16 @@ - + - net9.0 + net10.0 enable Unity.Notifications - - + + @@ -18,17 +18,16 @@ runtime; build; native; contentfiles; analyzers - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj index 006fe6bf22..d8a8029060 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj @@ -1,25 +1,24 @@ - + - net9.0 + net10.0 enable Unity.Payments - - - - - - - - - - - + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs index f510bb458e..b48f667800 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs @@ -77,6 +77,35 @@ public static AccountCoding Create( return new AccountCoding(ministryClient, responsibility, serviceLine, stob, projectNumber, description); } + public void Update( + string ministryClient, + string responsibility, + string serviceLine, + string stob, + string projectNumber, + string? description = null) + { + ValidateField(ministryClient, 3, nameof(MinistryClient), false); + ValidateField(responsibility, 5, nameof(Responsibility), false); + ValidateField(serviceLine, 5, nameof(serviceLine), true); + ValidateField(stob, 4, nameof(stob), true); + ValidateField(projectNumber, 7, nameof(projectNumber), true); + + if (!string.IsNullOrWhiteSpace(description) && description.Length > 35) + { + throw new BusinessException(ErrorConsts.InvalidAccountCodingField) + .WithData("field", nameof(Description)) + .WithData("length", 35); + } + + MinistryClient = ministryClient; + Responsibility = responsibility; + ServiceLine = serviceLine; + Stob = stob; + ProjectNumber = projectNumber; + Description = description; + } + private static void ValidateField(string field, uint length, string fieldName, bool validateAlphanumeric) { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs deleted file mode 100644 index bde9647f92..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs +++ /dev/null @@ -1,84 +0,0 @@ -using AutoMapper; -using Unity.GrantManager.Applications; -using Unity.GrantManager.GlobalTag; -using Unity.GrantManager.Payments; -using Unity.Payments.Domain.AccountCodings; -using Unity.Payments.Domain.PaymentConfigurations; -using Unity.Payments.Domain.PaymentRequests; -using Unity.Payments.Domain.PaymentTags; -using Unity.Payments.Domain.PaymentThresholds; -using Unity.Payments.Domain.Suppliers; -using Unity.Payments.PaymentConfigurations; -using Unity.Payments.PaymentRequests; -using Unity.Payments.PaymentTags; -using Unity.Payments.PaymentThresholds; -using Unity.Payments.Suppliers; -using Volo.Abp.Users; - - -namespace Unity.Payments; - -public class PaymentsApplicationAutoMapperProfile : Profile -{ - public PaymentsApplicationAutoMapperProfile() - { - CreateMap() - .ForMember(dest => dest.ErrorSummary, opt => opt.Ignore()) - .ForMember(dest => dest.AccountCoding, opt => opt.MapFrom(src => src.AccountCoding)) - .ForMember(dest => dest.AccountCodingDisplay, opt => opt.Ignore()) - .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.Site)) - .ForMember(dest => dest.CreatorUser, opt => opt.Ignore()) - .ForMember(dest => dest.PaymentTags, opt => opt.MapFrom(src => src.PaymentTags)); - - CreateMap() - .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.Site)); - CreateMap() - .ForMember(x => x.DecisionUser, map => map.Ignore()); - CreateMap() - .ForMember(dest => dest.PaymentGroup, opt => opt.MapFrom(s => s.PaymentGroup.ToString())); - CreateMap(); - - CreateMap() - .ConstructUsing(src => AccountCoding.Create( - src.MinistryClient!, - src.Responsibility!, - src.ServiceLine!, - src.Stob!, - src.ProjectNumber!, - src.Description)) // This statement is used to support private setters - .ForMember(dest => dest.TenantId, opt => opt.Ignore()) - .ForMember(dest => dest.LastModificationTime, opt => opt.Ignore()) - .ForMember(dest => dest.LastModifierId, opt => opt.Ignore()) - .ForMember(dest => dest.CreationTime, opt => opt.Ignore()) - .ForMember(dest => dest.CreatorId, opt => opt.Ignore()) - .ForMember(dest => dest.ExtraProperties, opt => opt.Ignore()) - .ForMember(dest => dest.ConcurrencyStamp, opt => opt.Ignore()) - .ForMember(dest => dest.Id, opt => opt.Ignore()); - - CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap() - .ForMember(dest => dest.UserName, opt => opt.Ignore()); - CreateMap() - .ForMember(dest => dest.UserName, opt => opt.Ignore()); - CreateMap() - .ForMember(dest => dest.TenantId, opt => opt.Ignore()) - .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) - .ForMember(dest => dest.DeleterId, opt => opt.Ignore()) - .ForMember(dest => dest.DeletionTime, opt => opt.Ignore()) - .ForMember(dest => dest.LastModificationTime, opt => opt.Ignore()) - .ForMember(dest => dest.LastModifierId, opt => opt.Ignore()) - .ForMember(dest => dest.CreationTime, opt => opt.Ignore()) - .ForMember(dest => dest.CreatorId, opt => opt.Ignore()) - .ForMember(dest => dest.ExtraProperties, opt => opt.Ignore()) - .ForMember(dest => dest.ConcurrencyStamp, opt => opt.Ignore()) - .ForMember(dest => dest.Id, opt => opt.Ignore()); - CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap(); - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationMapperlyProfile.cs new file mode 100644 index 0000000000..2eb6dcf743 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationMapperlyProfile.cs @@ -0,0 +1,190 @@ +using Riok.Mapperly.Abstractions; +using Unity.GrantManager.Applications; +using Unity.GrantManager.GlobalTag; +using Unity.GrantManager.Payments; +using Unity.Payments.Domain.AccountCodings; +using Unity.Payments.Domain.PaymentConfigurations; +using Unity.Payments.Domain.PaymentRequests; +using Unity.Payments.Domain.PaymentTags; +using Unity.Payments.Domain.PaymentThresholds; +using Unity.Payments.Domain.Suppliers; +using Unity.Payments.PaymentConfigurations; +using Unity.Payments.PaymentRequests; +using Unity.Payments.PaymentTags; +using Unity.Payments.PaymentThresholds; +using Unity.Payments.Suppliers; +using Volo.Abp.Mapperly; +using Volo.Abp.Users; + +namespace Unity.Payments; + +[Mapper(AllowNullPropertyAssignment = true)] +public partial class PaymentRequestToPaymentRequestDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(PaymentRequestDto.ErrorSummary))] + [MapperIgnoreTarget(nameof(PaymentRequestDto.AccountCodingDisplay))] + [MapperIgnoreTarget(nameof(PaymentRequestDto.CreatorUser))] + public override partial PaymentRequestDto Map(PaymentRequest source); + + [MapperIgnoreTarget(nameof(PaymentRequestDto.ErrorSummary))] + [MapperIgnoreTarget(nameof(PaymentRequestDto.AccountCodingDisplay))] + [MapperIgnoreTarget(nameof(PaymentRequestDto.CreatorUser))] + public override partial void Map(PaymentRequest source, PaymentRequestDto destination); + + [MapperIgnoreTarget(nameof(ExpenseApprovalDto.DecisionUser))] + private partial ExpenseApprovalDto MapExpenseApproval(ExpenseApproval source); +} + +[Mapper] +public partial class PaymentRequestToPaymentDetailsDtoMapper : MapperBase +{ + public override partial PaymentDetailsDto Map(PaymentRequest source); + public override partial void Map(PaymentRequest source, PaymentDetailsDto destination); + + [MapperIgnoreTarget(nameof(ExpenseApprovalDto.DecisionUser))] + private partial ExpenseApprovalDto MapExpenseApproval(ExpenseApproval source); +} + +[Mapper] +public partial class ExpenseApprovalToExpenseApprovalDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ExpenseApprovalDto.DecisionUser))] + public override partial ExpenseApprovalDto Map(ExpenseApproval source); + + [MapperIgnoreTarget(nameof(ExpenseApprovalDto.DecisionUser))] + public override partial void Map(ExpenseApproval source, ExpenseApprovalDto destination); +} + +[Mapper] +public partial class SiteToSiteDtoMapper : MapperBase +{ + public override partial SiteDto Map(Site source); + public override partial void Map(Site source, SiteDto destination); +} + +[Mapper] +public partial class SupplierToSupplierDtoMapper : MapperBase +{ + public override partial SupplierDto Map(Supplier source); + public override partial void Map(Supplier source, SupplierDto destination); +} + +public class CreateUpdateAccountCodingDtoToAccountCodingMapper : MapperBase +{ + public override AccountCoding Map(CreateUpdateAccountCodingDto source) + { + return AccountCoding.Create( + source.MinistryClient!, + source.Responsibility!, + source.ServiceLine!, + source.Stob!, + source.ProjectNumber!, + source.Description); + } + + public override void Map(CreateUpdateAccountCodingDto source, AccountCoding destination) + { + destination.Update( + source.MinistryClient!, + source.Responsibility!, + source.ServiceLine!, + source.Stob!, + source.ProjectNumber!, + source.Description); + } +} + +[Mapper] +public partial class PaymentConfigurationToPaymentConfigurationDtoMapper : MapperBase +{ + public override partial PaymentConfigurationDto Map(PaymentConfiguration source); + public override partial void Map(PaymentConfiguration source, PaymentConfigurationDto destination); +} + +[Mapper] +public partial class AccountCodingToAccountCodingDtoMapper : MapperBase +{ + public override partial AccountCodingDto Map(AccountCoding source); + public override partial void Map(AccountCoding source, AccountCodingDto destination); +} + +[Mapper] +public partial class AccountCodingDtoToCreateUpdateAccountCodingDtoMapper : MapperBase +{ + public override partial CreateUpdateAccountCodingDto Map(AccountCodingDto source); + public override partial void Map(AccountCodingDto source, CreateUpdateAccountCodingDto destination); +} + +[Mapper] +public partial class PaymentThresholdDtoToUpdatePaymentThresholdDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(UpdatePaymentThresholdDto.UserName))] + public override partial UpdatePaymentThresholdDto Map(PaymentThresholdDto source); + + [MapperIgnoreTarget(nameof(UpdatePaymentThresholdDto.UserName))] + public override partial void Map(PaymentThresholdDto source, UpdatePaymentThresholdDto destination); +} + +[Mapper] +public partial class PaymentThresholdToPaymentThresholdDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(PaymentThresholdDto.UserName))] + public override partial PaymentThresholdDto Map(PaymentThreshold source); + + [MapperIgnoreTarget(nameof(PaymentThresholdDto.UserName))] + public override partial void Map(PaymentThreshold source, PaymentThresholdDto destination); +} + +[Mapper] +public partial class UpdatePaymentThresholdDtoToPaymentThresholdMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(PaymentThreshold.TenantId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.IsDeleted))] + [MapperIgnoreTarget(nameof(PaymentThreshold.DeleterId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.DeletionTime))] + [MapperIgnoreTarget(nameof(PaymentThreshold.LastModificationTime))] + [MapperIgnoreTarget(nameof(PaymentThreshold.LastModifierId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.CreationTime))] + [MapperIgnoreTarget(nameof(PaymentThreshold.CreatorId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.ConcurrencyStamp))] + public override partial PaymentThreshold Map(UpdatePaymentThresholdDto source); + + [MapperIgnoreTarget(nameof(PaymentThreshold.TenantId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.IsDeleted))] + [MapperIgnoreTarget(nameof(PaymentThreshold.DeleterId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.DeletionTime))] + [MapperIgnoreTarget(nameof(PaymentThreshold.LastModificationTime))] + [MapperIgnoreTarget(nameof(PaymentThreshold.LastModifierId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.CreationTime))] + [MapperIgnoreTarget(nameof(PaymentThreshold.CreatorId))] + [MapperIgnoreTarget(nameof(PaymentThreshold.ConcurrencyStamp))] + public override partial void Map(UpdatePaymentThresholdDto source, PaymentThreshold destination); +} + +[Mapper] +public partial class UserDataToPaymentUserDtoMapper : MapperBase +{ + public override partial PaymentUserDto Map(IUserData source); + public override partial void Map(IUserData source, PaymentUserDto destination); +} + +[Mapper] +public partial class TagToGlobalTagDtoMapper : MapperBase +{ + public override partial GlobalTagDto Map(Tag source); + public override partial void Map(Tag source, GlobalTagDto destination); +} + +[Mapper] +public partial class PaymentTagToPaymentTagDtoMapper : MapperBase +{ + public override partial PaymentTagDto Map(PaymentTag source); + public override partial void Map(PaymentTag source, PaymentTagDto destination); +} + +[Mapper] +public partial class TagSummaryCountToTagSummaryCountDtoMapper : MapperBase +{ + public override partial TagSummaryCountDto Map(TagSummaryCount source); + public override partial void Map(TagSummaryCount source, TagSummaryCountDto destination); +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationModule.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationModule.cs index db352a16aa..9915f3b514 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationModule.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.Application; using Volo.Abp.VirtualFileSystem; @@ -23,7 +23,7 @@ namespace Unity.Payments; typeof(UnityAuditingOverrideModule), typeof(AbpVirtualFileSystemModule), typeof(AbpDddApplicationModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpVirtualFileSystemModule), typeof(PaymentsApplicationContractsModule), typeof(AbpBackgroundJobsModule), @@ -57,11 +57,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); context.Services.AddHttpClientProxies( typeof(PaymentsApplicationContractsModule).Assembly, diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Unity.Payments.Application.csproj b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Unity.Payments.Application.csproj index 294192225a..b1cad6e2c4 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Unity.Payments.Application.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Unity.Payments.Application.csproj @@ -1,36 +1,37 @@ - + - net9.0 + net10.0 enable Unity.Payments - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Unity.Payments.Shared.csproj b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Unity.Payments.Shared.csproj index 9201a7aaa6..03b6952acd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Unity.Payments.Shared.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Unity.Payments.Shared.csproj @@ -1,26 +1,25 @@ - + - net9.0 + net10.0 enable Unity.Payments true - - - - - - - + + + + + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/PaymentsWebAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/PaymentsWebAutoMapperProfile.cs deleted file mode 100644 index f0d5cc13a7..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/PaymentsWebAutoMapperProfile.cs +++ /dev/null @@ -1,11 +0,0 @@ -using AutoMapper; - -namespace Unity.Payments.Web; - -public class PaymentsWebAutoMapperProfile : Profile -{ - public PaymentsWebAutoMapperProfile() - { - // Intentionally left blank - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/PaymentsWebModule.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/PaymentsWebModule.cs index fe60abfdb4..0aeb0fb4af 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/PaymentsWebModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/PaymentsWebModule.cs @@ -4,7 +4,7 @@ using Unity.Payments.Web.Menus; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.UI.Navigation; using Volo.Abp.VirtualFileSystem; @@ -14,7 +14,7 @@ namespace Unity.Payments.Web; [DependsOn( typeof(PaymentsApplicationContractsModule), typeof(AbpAspNetCoreMvcUiThemeSharedModule), - typeof(AbpAutoMapperModule) + typeof(AbpMapperlyModule) )] public class PaymentsWebModule : AbpModule { @@ -43,11 +43,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); Configure(options => { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Unity.Payments.Web.csproj b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Unity.Payments.Web.csproj index 5b30a7e696..35a005262d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Unity.Payments.Web.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Unity.Payments.Web.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable true Library @@ -12,18 +12,17 @@ - - - - - - - - + + + + + + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/Unity.Payments.Application.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/Unity.Payments.Application.Tests.csproj index 71873b876b..e0871d7f80 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/Unity.Payments.Application.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/Unity.Payments.Application.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.Payments @@ -13,15 +13,14 @@ - - + + - - - + + - - + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.TestBase/Unity.Payments.TestBase.csproj b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.TestBase/Unity.Payments.TestBase.csproj index ff5f727d58..5ed17173ab 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.TestBase/Unity.Payments.TestBase.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.TestBase/Unity.Payments.TestBase.csproj @@ -1,16 +1,16 @@ - + - net9.0 + net10.0 enable Unity.Payments - - + + @@ -18,30 +18,31 @@ runtime; build; native; contentfiles; analyzers - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application.Contracts/Unity.Reporting.Application.Contracts.csproj b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application.Contracts/Unity.Reporting.Application.Contracts.csproj index f72c98d808..c5e4928327 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application.Contracts/Unity.Reporting.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application.Contracts/Unity.Reporting.Application.Contracts.csproj @@ -1,16 +1,16 @@ - + - net9.0 + net10.0 enable Unity.Reporting - - + + diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationAutoMapperProfile.cs deleted file mode 100644 index f1c0a47ea3..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationAutoMapperProfile.cs +++ /dev/null @@ -1,50 +0,0 @@ -using AutoMapper; -using System.Text.Json; -using Unity.Reporting.Configuration; -using Unity.Reporting.Domain.Configuration; - -namespace Unity.Reporting; - -/// -/// AutoMapper configuration profile for Unity.Reporting module defining mappings between domain entities and DTOs. -/// Handles complex object transformations including JSON deserialization of mapping configuration data -/// and proper conversion between ReportColumnsMap entities and their corresponding data transfer objects. -/// -public class ReportingApplicationAutoMapperProfile : Profile -{ - public ReportingApplicationAutoMapperProfile() - { - // Entity to DTO (Read operations) - CreateMap() - .ForMember(dest => dest.Mapping, opt => opt.ConvertUsing(src => src.Mapping)) - .ForMember(dest => dest.DetectedChanges, opt => opt.Ignore()); - - CreateMap(); - CreateMap(); - } - - /// - /// Custom AutoMapper value converter for deserializing JSON mapping strings into MappingDto objects. - /// Provides safe JSON deserialization with error handling and fallback to empty mapping objects - /// when source data is invalid or malformed. - /// - private sealed class MappingJsonConverter : IValueConverter - { - public MappingDto Convert(string sourceMember, ResolutionContext context) - { - if (string.IsNullOrWhiteSpace(sourceMember)) - { - return new MappingDto(); - } - - try - { - return JsonSerializer.Deserialize(sourceMember, (JsonSerializerOptions?)null) ?? new MappingDto(); - } - catch - { - return new MappingDto(); - } - } - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationMapperlyProfile.cs new file mode 100644 index 0000000000..134acf454e --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationMapperlyProfile.cs @@ -0,0 +1,51 @@ +using System.Text.Json; +using Riok.Mapperly.Abstractions; +using Unity.Reporting.Configuration; +using Unity.Reporting.Domain.Configuration; +using Volo.Abp.Mapperly; + +namespace Unity.Reporting; + +[Mapper] +public partial class ReportColumnsMapToReportColumnsMapDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ReportColumnsMapDto.DetectedChanges))] + public override partial ReportColumnsMapDto Map(ReportColumnsMap source); + + [MapperIgnoreTarget(nameof(ReportColumnsMapDto.DetectedChanges))] + public override partial void Map(ReportColumnsMap source, ReportColumnsMapDto destination); + + [UserMapping] + private static MappingDto MapMappingJson(string source) + { + if (string.IsNullOrWhiteSpace(source)) + { + return new MappingDto(); + } + + try + { + return JsonSerializer.Deserialize(source, (JsonSerializerOptions?)null) ?? new MappingDto(); + } + catch + { + return new MappingDto(); + } + } +} + +[Mapper] +public partial class MappingToMappingDtoMapper : MapperBase +{ + public override partial MappingDto Map(Mapping source); + + public override partial void Map(Mapping source, MappingDto destination); +} + +[Mapper] +public partial class MapRowToMapRowDtoMapper : MapperBase +{ + public override partial MapRowDto Map(MapRow source); + + public override partial void Map(MapRow source, MapRowDto destination); +} diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationModule.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationModule.cs index cb8375ac09..12a95d03a9 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/ReportingApplicationModule.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.Application; using Volo.Abp.MultiTenancy; @@ -20,7 +20,7 @@ namespace Unity.Reporting; typeof(ReportingApplicationContractsModule), typeof(ReportingEntityFrameworkCoreModule), typeof(AbpDddApplicationModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpSettingManagementApplicationModule), typeof(AbpTenantManagementDomainModule) )] @@ -46,11 +46,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); context.Services.AddHttpClientProxies( typeof(ReportingApplicationContractsModule).Assembly, diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/Unity.Reporting.Application.csproj b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/Unity.Reporting.Application.csproj index 4d171a8616..d9f72545c4 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/Unity.Reporting.Application.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Application/Unity.Reporting.Application.csproj @@ -1,20 +1,21 @@ - + - net9.0 + net10.0 enable Unity.Reporting - - - - - - + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Domain.Shared/Unity.Reporting.Shared.csproj b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Domain.Shared/Unity.Reporting.Shared.csproj index b72a59b95a..aa2aa2c826 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Domain.Shared/Unity.Reporting.Shared.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Domain.Shared/Unity.Reporting.Shared.csproj @@ -1,21 +1,21 @@ - + - net9.0 + net10.0 enable Unity.Reporting true - - + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/ReportingWebAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/ReportingWebAutoMapperProfile.cs deleted file mode 100644 index 6eae1d14b0..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/ReportingWebAutoMapperProfile.cs +++ /dev/null @@ -1,22 +0,0 @@ -using AutoMapper; - -namespace Unity.Reporting.Web; - -/// -/// AutoMapper configuration profile for Unity.Reporting Web module defining mappings between domain objects and view models. -/// Currently intentionally left blank as no specific web-layer object mappings are required, -/// but serves as the registration point for any future web-specific AutoMapper configurations -/// such as domain entities to view models or DTOs to presentation models. -/// -public class ReportingWebAutoMapperProfile : Profile -{ - /// - /// Initializes a new instance of the ReportingWebAutoMapperProfile. - /// Currently intentionally left blank as no web-layer specific mappings are needed, - /// but can be extended to include view model transformations as requirements evolve. - /// - public ReportingWebAutoMapperProfile() - { - // Intentionally left blank - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/ReportingWebModule.cs b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/ReportingWebModule.cs index e47ebe3394..34b15c6436 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/ReportingWebModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/ReportingWebModule.cs @@ -3,7 +3,7 @@ using Unity.Reporting.Web.Menus; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.SettingManagement.Web; using Volo.Abp.UI.Navigation; @@ -20,7 +20,7 @@ namespace Unity.Reporting.Web; [DependsOn( typeof(ReportingApplicationContractsModule), typeof(AbpAspNetCoreMvcUiThemeSharedModule), - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpSettingManagementWebModule) )] public class ReportingWebModule : AbpModule @@ -62,10 +62,6 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Unity.Reporting.Web.csproj b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Unity.Reporting.Web.csproj index a98521f3f5..4798a9d065 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Unity.Reporting.Web.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/src/Unity.Reporting.Web/Unity.Reporting.Web.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable true Library @@ -12,17 +12,16 @@ - - - - - - - + + + + + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.Application.Tests/Unity.Reporting.Application.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.Application.Tests/Unity.Reporting.Application.Tests.csproj index ca6484286c..c7c03b191a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.Application.Tests/Unity.Reporting.Application.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.Application.Tests/Unity.Reporting.Application.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.Reporting @@ -11,7 +11,7 @@ - + diff --git a/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.TestBase/Unity.Reporting.TestBase.csproj b/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.TestBase/Unity.Reporting.TestBase.csproj index 75915cbe61..8cd7e3b79e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.TestBase/Unity.Reporting.TestBase.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Reporting/test/Unity.Reporting.TestBase/Unity.Reporting.TestBase.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.Reporting @@ -22,10 +22,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Auditing/UnityAuditingHelper.cs b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Auditing/UnityAuditingHelper.cs index 821b06ccc2..e1c6d1330b 100644 --- a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Auditing/UnityAuditingHelper.cs +++ b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Auditing/UnityAuditingHelper.cs @@ -75,5 +75,15 @@ public AuditLogActionInfo CreateAuditLogAction( { return _inner.CreateAuditLogAction(auditLog, type, method, arguments); } + + public IDisposable DisableAuditing() + { + return _inner.DisableAuditing(); + } + + public bool IsAuditingEnabled() + { + return _inner.IsAuditingEnabled(); + } } diff --git a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Unity.SharedKernel.csproj b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Unity.SharedKernel.csproj index a24ca603f7..ef4d1c6ff8 100644 --- a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Unity.SharedKernel.csproj +++ b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Unity.SharedKernel.csproj @@ -3,7 +3,7 @@ - net9.0 + net10.0 enable Unity.Modules.Shared @@ -14,17 +14,16 @@ all runtime; build; native; contentfiles; analyzers - - + + - - - - - - - - - + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application.Contracts/Unity.TenantManagement.Application.Contracts.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application.Contracts/Unity.TenantManagement.Application.Contracts.csproj index d1708029e6..46ef69fa14 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application.Contracts/Unity.TenantManagement.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application.Contracts/Unity.TenantManagement.Application.Contracts.csproj @@ -1,6 +1,6 @@ - + latest - netstandard2.1;net9.0 + netstandard2.1;net10.0 Unity.TenantManagement.Application.Contracts Unity.TenantManagement.Application.Contracts false @@ -9,12 +9,12 @@ - - - - - - + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/Unity.TenantManagement.Application.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/Unity.TenantManagement.Application.csproj index 53430a334f..ece4db4b9b 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/Unity.TenantManagement.Application.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/Unity.TenantManagement.Application.csproj @@ -1,6 +1,6 @@ - + latest - net9.0 + net10.0 Unity.TenantManagement.Application Unity.TenantManagement.Application false @@ -9,14 +9,15 @@ - - - - - - - - + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationAutoMapperProfile.cs deleted file mode 100644 index 94af136452..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationAutoMapperProfile.cs +++ /dev/null @@ -1,14 +0,0 @@ -using AutoMapper; -using Volo.Abp.TenantManagement; - -namespace Unity.TenantManagement; - -public class UnityTenantManagementApplicationAutoMapperProfile : Profile -{ - public UnityTenantManagementApplicationAutoMapperProfile() - { - CreateMap() - .MapExtraProperties(); - } -} - diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs index 7b1d7a9612..98cc1dbb0c 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementApplicationModule.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.TenantManagement; @@ -9,18 +9,13 @@ namespace Unity.TenantManagement typeof(AbpTenantManagementDomainModule), typeof(UnityTenantManagementApplicationContractsModule), typeof(AbpTenantManagementApplicationModule), - typeof(AbpAutoMapperModule) + typeof(AbpMapperlyModule) )] public class UnityTenantManagementApplicationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddAutoMapperObjectMapper(); - - Configure(options => - { - options.AddMaps(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); } } } diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs deleted file mode 100644 index 8c11a3282c..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementAutoMapperProfile.cs +++ /dev/null @@ -1,28 +0,0 @@ -#nullable enable - -using AutoMapper; -using Volo.Abp.TenantManagement; - -namespace Unity.TenantManagement -{ - public class UnityTenantManagementAutoMapperProfile : Profile - { - public UnityTenantManagementAutoMapperProfile() - { - CreateMap() - .ForMember(dest => dest.CasClientCode, opt => opt.MapFrom(src => - GetExtraProperty(src, "CasClientCode"))) - .ForMember(dest => dest.Division, opt => opt.MapFrom(src => - GetExtraProperty(src, "Division"))) - .ForMember(dest => dest.Branch, opt => opt.MapFrom(src => - GetExtraProperty(src, "Branch"))) - .ForMember(dest => dest.Description, opt => opt.MapFrom(src => - GetExtraProperty(src, "Description"))); - } - - private static string? GetExtraProperty(Tenant tenant, string key) - { - return tenant.ExtraProperties.TryGetValue(key, out var value) ? value?.ToString() : null; - } - } -} \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementMapperlyProfile.cs new file mode 100644 index 0000000000..2d806371cf --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Application/UnityTenantManagementMapperlyProfile.cs @@ -0,0 +1,37 @@ +#nullable enable + +using Volo.Abp.Mapperly; +using Volo.Abp.TenantManagement; + +namespace Unity.TenantManagement; + +public class TenantToTenantDtoMapper : MapperBase +{ + public override TenantDto Map(Tenant source) + { + var destination = new TenantDto(); + Map(source, destination); + return destination; + } + + public override void Map(Tenant source, TenantDto destination) + { + destination.Id = source.Id; + destination.Name = source.Name; + destination.ConcurrencyStamp = source.ConcurrencyStamp; + destination.CasClientCode = GetExtraProperty(source, "CasClientCode") ?? string.Empty; + destination.Division = GetExtraProperty(source, "Division") ?? string.Empty; + destination.Branch = GetExtraProperty(source, "Branch") ?? string.Empty; + destination.Description = GetExtraProperty(source, "Description") ?? string.Empty; + + foreach (var kvp in source.ExtraProperties) + { + destination.ExtraProperties[kvp.Key] = kvp.Value; + } + } + + private static string? GetExtraProperty(Tenant tenant, string key) + { + return tenant.ExtraProperties.TryGetValue(key, out var value) ? value?.ToString() : null; + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi.Client/Unity.TenantManagement.HttpApi.Client.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi.Client/Unity.TenantManagement.HttpApi.Client.csproj index 18aff4a398..0be2b80c6a 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi.Client/Unity.TenantManagement.HttpApi.Client.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi.Client/Unity.TenantManagement.HttpApi.Client.csproj @@ -1,8 +1,8 @@ - + latest - netstandard2.1;net9.0 + netstandard2.1;net10.0 Unity.TenantManagement.HttpApi.Client Unity.TenantManagement.HttpApi.Client false @@ -11,9 +11,9 @@ - - - + + + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi/Unity.TenantManagement.HttpApi.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi/Unity.TenantManagement.HttpApi.csproj index 1f28c0a783..4be4c28fee 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi/Unity.TenantManagement.HttpApi.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.HttpApi/Unity.TenantManagement.HttpApi.csproj @@ -1,7 +1,7 @@ - + latest - net9.0 + net10.0 Unity.TenantManagement.HttpApi Unity.TenantManagement.HttpApi false @@ -12,14 +12,12 @@ - + - + - - - - + + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/MapperlyDefaults.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Unity.TenantManagement.Web.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Unity.TenantManagement.Web.csproj index 8b34a62a24..c4e99d3d6c 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Unity.TenantManagement.Web.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Unity.TenantManagement.Web.csproj @@ -1,6 +1,6 @@ - + latest - net9.0 + net10.0 Unity.TenantManagement.Web Unity.TenantManagement.Web true @@ -28,16 +28,14 @@ - - - - + - + + - + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebAutoMapperProfile.cs deleted file mode 100644 index 7f68542624..0000000000 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebAutoMapperProfile.cs +++ /dev/null @@ -1,33 +0,0 @@ -using AutoMapper; -using Unity.TenantManagement.Web.Pages.TenantManagement.Tenants; -using static Unity.TenantManagement.Web.Pages.TenantManagement.Tenants.AssignManagerModalModel; - -namespace Unity.TenantManagement.Web; - -public class AbpTenantManagementWebAutoMapperProfile : Profile -{ - public AbpTenantManagementWebAutoMapperProfile() - { - //List - CreateMap() - .MapExtraProperties(); - - //CreateModal - CreateMap() - .MapExtraProperties(); - - //EditModal - CreateMap() - .MapExtraProperties(); - - //AssignManagerModal - CreateMap() - .ForMember(dest => dest.Id, opt => opt.MapFrom(s => s.Id)) - .ForMember(dest => dest.Name, opt => opt.MapFrom(s => s.Name)) - .ForMember(dest => dest.FirstName, opt => opt.Ignore()) - .ForMember(dest => dest.LastName, opt => opt.Ignore()) - .ForMember(dest => dest.UserIdentifier, opt => opt.Ignore()) - .ForMember(dest => dest.Directory, opt => opt.Ignore()) - .MapExtraProperties(); - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebMapperlyProfile.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebMapperlyProfile.cs new file mode 100644 index 0000000000..2ff26b3542 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebMapperlyProfile.cs @@ -0,0 +1,98 @@ +using Unity.TenantManagement.Web.Pages.TenantManagement.Tenants; +using Volo.Abp.Mapperly; +using static Unity.TenantManagement.Web.Pages.TenantManagement.Tenants.AssignManagerModalModel; + +namespace Unity.TenantManagement.Web; + +internal static class TenantExtraPropertiesCopier +{ + public static void Copy(Volo.Abp.Data.IHasExtraProperties source, Volo.Abp.Data.IHasExtraProperties destination) + { + foreach (var kvp in source.ExtraProperties) + { + destination.ExtraProperties[kvp.Key] = kvp.Value; + } + } +} + +public class TenantDtoToEditTenantInfoMapper : MapperBase +{ + public override EditModalModel.TenantInfoModel Map(TenantDto source) + { + var destination = new EditModalModel.TenantInfoModel(); + Map(source, destination); + return destination; + } + + public override void Map(TenantDto source, EditModalModel.TenantInfoModel destination) + { + destination.Id = source.Id; + destination.Name = source.Name; + destination.Division = source.Division; + destination.Branch = source.Branch; + destination.Description = source.Description; + destination.CasClientCode = source.CasClientCode; + destination.ConcurrencyStamp = source.ConcurrencyStamp; + TenantExtraPropertiesCopier.Copy(source, destination); + } +} + +public class CreateTenantInfoToTenantCreateDtoMapper : MapperBase +{ + public override TenantCreateDto Map(CreateModalModel.TenantInfoModel source) + { + var destination = new TenantCreateDto(); + Map(source, destination); + return destination; + } + + public override void Map(CreateModalModel.TenantInfoModel source, TenantCreateDto destination) + { + destination.Name = source.Name; + destination.Division = source.Division; + destination.Branch = source.Branch; + destination.Description = source.Description; + destination.CasClientCode = source.CasClientCode; + destination.UserIdentifier = source.UserIdentifier; + TenantExtraPropertiesCopier.Copy(source, destination); + } +} + +public class EditTenantInfoToTenantUpdateDtoMapper : MapperBase +{ + public override TenantUpdateDto Map(EditModalModel.TenantInfoModel source) + { + var destination = new TenantUpdateDto(); + Map(source, destination); + return destination; + } + + public override void Map(EditModalModel.TenantInfoModel source, TenantUpdateDto destination) + { + destination.Name = source.Name; + destination.Division = source.Division; + destination.Branch = source.Branch; + destination.Description = source.Description; + destination.CasClientCode = source.CasClientCode; + destination.ConcurrencyStamp = source.ConcurrencyStamp; + TenantExtraPropertiesCopier.Copy(source, destination); + } +} + +public class TenantDtoToAssignManagerInfoMapper : MapperBase +{ + public override AssignManagerInfoModel Map(TenantDto source) + { + var destination = new AssignManagerInfoModel(); + Map(source, destination); + return destination; + } + + public override void Map(TenantDto source, AssignManagerInfoModel destination) + { + destination.Id = source.Id; + destination.Name = source.Name; + destination.ConcurrencyStamp = source.ConcurrencyStamp; + TenantExtraPropertiesCopier.Copy(source, destination); + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebModule.cs b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebModule.cs index 47f2e4f79f..08f08f4142 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebModule.cs +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/UnityTenantManagementWebModule.cs @@ -3,7 +3,7 @@ using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.FeatureManagement; using Volo.Abp.Http.ProxyScripting.Generators.JQuery; using Volo.Abp.Localization; @@ -21,7 +21,7 @@ namespace Unity.TenantManagement.Web; [DependsOn(typeof(UnityTenantManagementApplicationContractsModule))] [DependsOn(typeof(AbpAspNetCoreMvcUiBootstrapModule))] [DependsOn(typeof(AbpFeatureManagementWebModule))] -[DependsOn(typeof(AbpAutoMapperModule))] +[DependsOn(typeof(AbpMapperlyModule))] public class UnityTenantManagementWebModule : AbpModule { private static readonly OneTimeRunner OneTimeRunner = new(); @@ -51,11 +51,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); - context.Services.AddAutoMapperObjectMapper(); - Configure(options => - { - options.AddProfile(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); Configure(options => { diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.Application.Tests/Unity.TenantManagement.Application.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.Application.Tests/Unity.TenantManagement.Application.Tests.csproj index fd22d2f4f2..48b9e1753a 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.Application.Tests/Unity.TenantManagement.Application.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.Application.Tests/Unity.TenantManagement.Application.Tests.csproj @@ -1,7 +1,7 @@ - + latest - net9.0 + net10.0 Unity.TenantManagement.Application.Tests Unity.TenantManagement.Application.Tests true @@ -18,13 +18,12 @@ - - - + + + - - + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.EntityFrameworkCore.Tests/Unity.TenantManagement.EntityFrameworkCore.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.EntityFrameworkCore.Tests/Unity.TenantManagement.EntityFrameworkCore.Tests.csproj index 511db9ce2f..6561e399e8 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.EntityFrameworkCore.Tests/Unity.TenantManagement.EntityFrameworkCore.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.EntityFrameworkCore.Tests/Unity.TenantManagement.EntityFrameworkCore.Tests.csproj @@ -1,7 +1,7 @@ - + latest - net9.0 + net10.0 Unity.TenantManagement.EntityFrameworkCore.Tests Unity.TenantManagement.EntityFrameworkCore.Tests true @@ -13,17 +13,16 @@ - - - - - + + + + - - + + diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.TestBase/Unity.TenantManagement.TestBase.csproj b/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.TestBase/Unity.TenantManagement.TestBase.csproj index d0efac359b..3980e31fd6 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.TestBase/Unity.TenantManagement.TestBase.csproj +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/test/Unity.TenantManagement.TestBase/Unity.TenantManagement.TestBase.csproj @@ -1,7 +1,7 @@ - + latest - net9.0 + net10.0 Unity.TenantManagement.TestBase Unity.TenantManagement.TestBase true @@ -12,17 +12,16 @@ - - - + + + - - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Unity.AspNetCore.Mvc.UI.Theme.UX2.csproj b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Unity.AspNetCore.Mvc.UI.Theme.UX2.csproj index 692e021272..fdab8629aa 100644 --- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Unity.AspNetCore.Mvc.UI.Theme.UX2.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Unity.AspNetCore.Mvc.UI.Theme.UX2.csproj @@ -1,7 +1,7 @@ - + latest - net9.0 + net10.0 true Unity.AspNetCore.Mvc.UI.Themes Unity.AspNetCore.Mvc.UI.Themes @@ -23,11 +23,10 @@ - - - - - + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj index 3cbf5e2fa7..4f55729056 100644 --- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj @@ -1,7 +1,7 @@ - + - net9.0 + net10.0 enable enable diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs index 0351e6aecb..866085f414 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs @@ -22,7 +22,7 @@ public class ApplicationFormDto : EntityDto public DateTime? AttemptedConnectionDate { get; set; } public bool Payable { get; set; } public bool PreventPayment { get; set; } - public Guid AccountCodingId { get; set; } + public Guid? AccountCodingId { get; set; } public bool RenderFormIoToHtml { get; set; } public Guid? ScoresheetId { get; set; } public Guid? TenantId { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationApplicant.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationApplicant.cs index 47bf055e8a..b5f642253c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationApplicant.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationApplicant.cs @@ -1,4 +1,4 @@ -using System; +using System; using Volo.Abp.Application.Dtos; namespace Unity.GrantManager.GrantApplications; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs index 927a8c3728..1f703d5204 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/GrantApplicationDto.cs @@ -15,31 +15,31 @@ public class GrantApplicationDto : AuditedEntityDto public ApplicationFormDto ApplicationForm { get; set; } = new(); public string ReferenceNo { get; set; } = string.Empty; public decimal RequestedAmount { get; set; } - public List Assignees { get; set; } = new(); + public List Assignees { get; set; } = []; public DateTime SubmissionDate { get; set; } public string Status { get; set; } = string.Empty; public int Probability { get; set; } - public DateTime ProposalDate { get; set; } - public List ApplicationLinks { get; set; } = new(); - public string ApplicationName { get; set; } = string.Empty; + public DateTime? ProposalDate { get; set; } + public List? ApplicationLinks { get; set; } = []; + public string? ApplicationName { get; set; } = string.Empty; public string Category { get; set; } = string.Empty; - public string EconomicRegion { get; set; } = string.Empty; - public string City { get; set; } = string.Empty; + public string? EconomicRegion { get; set; } = string.Empty; + public string? City { get; set; } = string.Empty; public decimal TotalProjectBudget { get; set; } public string? Sector { get; set; } = string.Empty; public string? SubSector { get; set; } = string.Empty; - public string ProjectSummary { get; set; } = string.Empty; - public int TotalScore { get; set; } = 0; + public string? ProjectSummary { get; set; } = string.Empty; + public int? TotalScore { get; set; } = 0; public decimal RecommendedAmount { get; set; } = 0; public decimal ApprovedAmount { get; set; } = 0; - public string LikelihoodOfFunding { get; set; } = string.Empty; - public string DueDiligenceStatus { get; set; } = string.Empty; - public string SubStatus { get; set; } = string.Empty; + public string? LikelihoodOfFunding { get; set; } = string.Empty; + public string? DueDiligenceStatus { get; set; } = string.Empty; + public string? SubStatus { get; set; } = string.Empty; public string SubStatusDisplayValue { get; set; } = string.Empty; - public string DeclineRational { get; set; } = string.Empty; - public string Notes { get; set; } = string.Empty; - public string AssessmentResultStatus { get; set; } = string.Empty; - public DateTime AssessmentResultDate { get; set; } + public string? DeclineRational { get; set; } = string.Empty; + public string? Notes { get; set; } = string.Empty; + public string? AssessmentResultStatus { get; set; } = string.Empty; + public DateTime? AssessmentResultDate { get; set; } public GrantApplicationState StatusCode { get; set; } public DateTime? FinalDecisionDate { get; set; } public DateTime? DueDate { get; set; } @@ -65,7 +65,7 @@ public class GrantApplicationDto : AuditedEntityDto public string? OrganizationName { get; set; } public string? NonRegOrgName { get; set; } public string? OrganizationType { get; set; } - public GrantApplicationAssigneeDto Owner { get; set; } = new(); + public GrantApplicationAssigneeDto? Owner { get; set; } = new(); public string? OrgStatus { get; set; } = string.Empty; public string? BusinessNumber { get; set; } = string.Empty; public string? OrganizationSize { get; set; } = string.Empty; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Identity/IUserImportAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Identity/IUserImportAppService.cs index 6a542ac4a8..98e6eb7fb4 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Identity/IUserImportAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Identity/IUserImportAppService.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Services; @@ -9,5 +10,6 @@ public interface IUserImportAppService : IApplicationService Task AutoImportUserInternalAsync(ImportUserDto importUserDto, string username, string firstName, string lastName, string emailAddress, string oidcSub, string displayName); Task ImportUserAsync(ImportUserDto importUserDto); Task> SearchAsync(UserSearchDto importUserSearchDto); + Task SetUserRolesAsync(Guid userId, string[] roleNames); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj index 7df55afd60..7b1c8dcad2 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 enable Unity.GrantManager @@ -15,16 +15,13 @@ - - - - - - - - - + + + + + + **/Assessments/AssessmentListItemDto.cs, **/Assessments/AssessmentScoresDto.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/AttachmentPreviewAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/AttachmentPreviewAppService.cs index df2c80b7ca..1a4fba4af6 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/AttachmentPreviewAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/AttachmentPreviewAppService.cs @@ -10,11 +10,11 @@ namespace Unity.GrantManager.Attachments; -public class AttachmentPreviewAppService : ApplicationService, IAttachmentPreviewAppService, ITransientDependency, IDisposable +public class AttachmentPreviewAppService : ApplicationService, IAttachmentPreviewAppService, ITransientDependency { private readonly IFileAppService _fileAppService; private readonly ILibreOfficeConversionService _libreOfficeConversionService; - private readonly AmazonS3Client _amazonS3Client; + private readonly IAmazonS3 _amazonS3Client; private readonly string _bucket; private readonly string _applicationFolder; private readonly string _assessmentFolder; @@ -23,22 +23,12 @@ public class AttachmentPreviewAppService : ApplicationService, IAttachmentPrevie public AttachmentPreviewAppService( IFileAppService fileAppService, ILibreOfficeConversionService libreOfficeConversionService, - IConfiguration configuration) + IConfiguration configuration, + IAmazonS3 amazonS3Client) { _fileAppService = fileAppService; _libreOfficeConversionService = libreOfficeConversionService; - - var s3Config = new AmazonS3Config - { - RegionEndpoint = null, - ServiceURL = configuration["S3:Endpoint"], - AllowAutoRedirect = true, - ForcePathStyle = true - }; - _amazonS3Client = new AmazonS3Client( - configuration["S3:AccessKeyId"], - configuration["S3:SecretAccessKey"], - s3Config); + _amazonS3Client = amazonS3Client; _bucket = configuration["S3:Bucket"] ?? throw new InvalidOperationException("Missing server configuration: S3:Bucket"); _applicationFolder = NormalizeFolder(configuration["S3:ApplicationS3Folder"] ?? throw new InvalidOperationException("Missing server configuration: S3:ApplicationS3Folder")); @@ -165,17 +155,4 @@ private static string EscapeKeyFileName(string s3ObjectKey) if (lastSlash < 0) return Uri.EscapeDataString(s3ObjectKey); return s3ObjectKey[..(lastSlash + 1)] + Uri.EscapeDataString(s3ObjectKey[(lastSlash + 1)..]); } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _amazonS3Client.Dispose(); - } - } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs index e97eeea408..c744885522 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs @@ -1,19 +1,18 @@ -using Amazon.S3.Model; -using Amazon.S3; +using Amazon.S3; +using Amazon.S3.Model; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Primitives; using System; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Unity.GrantManager.Applications; using Volo.Abp.BlobStoring; using Volo.Abp.DependencyInjection; using Volo.Abp.Validation; -using Microsoft.AspNetCore.StaticFiles; -using Microsoft.Extensions.Configuration; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Routing; namespace Unity.GrantManager.Attachments; @@ -23,30 +22,15 @@ public partial class S3BlobProvider : BlobProviderBase, ITransientDependency private readonly IApplicationAttachmentRepository _applicationAttachmentRepository; private readonly IAssessmentAttachmentRepository _assessmentAttachmentRepository; private readonly IApplicantAttachmentRepository _applicantAttachmentRepository; - private readonly AmazonS3Client _amazonS3Client; + private readonly IAmazonS3 _amazonS3Client; - public S3BlobProvider(IHttpContextAccessor httpContextAccessor, IApplicationAttachmentRepository attachmentRepository, IAssessmentAttachmentRepository assessmentAttachmentRepository, IApplicantAttachmentRepository applicantAttachmentRepository, IConfiguration configuration) + public S3BlobProvider(IHttpContextAccessor httpContextAccessor, IApplicationAttachmentRepository attachmentRepository, IAssessmentAttachmentRepository assessmentAttachmentRepository, IApplicantAttachmentRepository applicantAttachmentRepository, IAmazonS3 amazonS3Client) { _httpContextAccessor = httpContextAccessor; _applicationAttachmentRepository = attachmentRepository; _assessmentAttachmentRepository = assessmentAttachmentRepository; _applicantAttachmentRepository = applicantAttachmentRepository; - - AmazonS3Config s3config = new() - { - RegionEndpoint = null, - ServiceURL = configuration["S3:Endpoint"], - AllowAutoRedirect = true, - ForcePathStyle = true - }; - - - AmazonS3Client s3Client = new( - configuration["S3:AccessKeyId"], - configuration["S3:SecretAccessKey"], - s3config - ); - _amazonS3Client = s3Client; + _amazonS3Client = amazonS3Client; } public override async Task DeleteAsync(BlobProviderDeleteArgs args) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Comments/CommentAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Comments/CommentAppService.cs index d1faf79bee..995b96fad0 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Comments/CommentAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Comments/CommentAppService.cs @@ -23,8 +23,8 @@ public async Task CreateAsync(CreateCommentByTypeDto dto) public async Task> GetListAsync(QueryCommentsByTypeDto dto) { - return ObjectMapper.Map, IReadOnlyList> - (await commentsManager.GetCommentsDisplayListAsync(dto.OwnerId, dto.CommentType)); + var comments = await commentsManager.GetCommentsDisplayListAsync(dto.OwnerId, dto.CommentType); + return ObjectMapper.Map, List>([.. comments]); } public async Task UpdateAsync(UpdateCommentByTypeDto dto) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/GenerateApplicationScoringJob.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/GenerateApplicationScoringJob.cs index 62900413b4..aa6bcb749b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/GenerateApplicationScoringJob.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/Automation/BackgroundJobs/GenerateApplicationScoringJob.cs @@ -2,9 +2,11 @@ using System; using System.Threading.Tasks; using Unity.GrantManager.GrantApplications; +using Unity.GrantManager.GrantApplications.Automation.Events; using Volo.Abp.BackgroundJobs; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; +using Volo.Abp.EventBus.Local; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; @@ -15,6 +17,7 @@ public class GenerateApplicationScoringJob( IRepository generationRequestRepository, ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, + ILocalEventBus localEventBus, ILogger logger) : AsyncBackgroundJob, ITransientDependency { public override async Task ExecuteAsync(GenerateApplicationScoringBackgroundJobArgs args) @@ -25,7 +28,14 @@ public override async Task ExecuteAsync(GenerateApplicationScoringBackgroundJobA try { logger.LogInformation("Executing AI application scoring job for application {ApplicationId}.", args.ApplicationId); - await applicationScoringAppService.GenerateApplicationScoringAsync(args.ApplicationId, args.PromptVersion); + var result = await applicationScoringAppService.GenerateApplicationScoringForPipelineAsync(args.ApplicationId, args.PromptVersion); + if (result.Completed) + { + await localEventBus.PublishAsync(new ApplicationAIScoringGeneratedEvent + { + ApplicationId = args.ApplicationId + }); + } logger.LogInformation("Completed AI application scoring job for application {ApplicationId}.", args.ApplicationId); await AIGenerationRequestJobHelper.MarkCompletedInNewUowAsync(unitOfWorkManager, generationRequestRepository, args.RequestKey); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs index a746d2e2bb..389934299c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -107,8 +107,8 @@ public async Task> GetListAsync(GrantApplica appDto.NonRegOrgName = app.Applicant?.NonRegOrgName ?? string.Empty; appDto.OrganizationType = app.Applicant?.OrganizationType ?? string.Empty; appDto.Assignees = BuildApplicationAssignees(app.ApplicationAssignments); - appDto.SubStatusDisplayValue = MapSubstatusDisplayValue(appDto.SubStatus); - appDto.DeclineRational = MapDeclineRationalDisplayValue(appDto.DeclineRational); + appDto.SubStatusDisplayValue = MapSubstatusDisplayValue(appDto.SubStatus ?? string.Empty); + appDto.DeclineRational = MapDeclineRationalDisplayValue(appDto.DeclineRational ?? string.Empty); appDto.ContactFullName = app.ApplicantAgent?.Name; appDto.ContactEmail = app.ApplicantAgent?.Email; appDto.ContactTitle = app.ApplicantAgent?.Title; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs deleted file mode 100644 index eed6cb79e6..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs +++ /dev/null @@ -1,220 +0,0 @@ -using AutoMapper; -using System; -using Unity.GrantManager.ApplicationForms; -using Unity.GrantManager.Applications; -using Unity.GrantManager.ApplicantProfile; -using Unity.GrantManager.Assessments; -using Unity.GrantManager.Attachments; -using Unity.GrantManager.Comments; -using Unity.GrantManager.Events; -using Unity.GrantManager.Forms; -using Unity.GrantManager.GlobalTag; -using Unity.GrantManager.GrantApplications; -using Unity.GrantManager.Identity; -using Unity.GrantManager.Intakes; -using Unity.GrantManager.Integrations; -using Unity.GrantManager.Locality; -using Unity.GrantManager.Zones; -using Unity.Payments.Domain.AccountCodings; -using Unity.Payments.PaymentRequests; - -namespace Unity.GrantManager; - -public class GrantManagerApplicationAutoMapperProfile : Profile -{ - public GrantManagerApplicationAutoMapperProfile() - { - /* You can configure your AutoMapper mapping configuration here. - * Alternatively, you can split your mapping configurations - * into multiple profile classes for a better organization. */ - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap(); - CreateMap(); - CreateMap() - .ForMember(d => d.AssigneeId, opt => opt.MapFrom(src => src.Id)) - .ForMember(d => d.FullName, opt => opt.MapFrom(src => src.FullName)) - .ForMember(d => d.ApplicationId, opt => opt.Ignore()) - .ForMember(d => d.Duty, opt => opt.Ignore()); - CreateMap(); - CreateMap() - .ForMember(dest => dest.OwnerId, opt => opt.MapFrom(src => src.AssessmentId)); - CreateMap() - .ForMember(dest => dest.OwnerId, opt => opt.MapFrom(src => src.ApplicationId)); - CreateMap() - .ForMember(dest => dest.OwnerId, opt => opt.MapFrom(src => src.ApplicantId)); - CreateMap() - .ForMember(dest => dest.Badge, opt => opt.MapFrom(src => src.CommenterBadge)) - .ForMember(dest => dest.Commenter, opt => opt.MapFrom(src => src.CommenterDisplayName)) - .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) - .ForMember(dest => dest.PinDateTime, opt => opt.MapFrom(src => src.PinDateTime)); - CreateMap() - .ForMember( - dest => dest.StartDate, - opts => opts.MapFrom(src => src.CreationTime)); - CreateMap() - .ForMember(d => d.SubTotal, opt => opt.Ignore()); - CreateMap() - .ForMember(dest => dest.CreatedTime, opt => opt.MapFrom(src => src.CreationTime)) - .ForMember(dest => dest.UpdatedTime, opt => opt.MapFrom(src => src.LastModificationTime)); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap().ReverseMap(); - CreateMap().ReverseMap(); - CreateMap().ReverseMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap() - .ForMember(dest => dest.Tag, opt => opt.MapFrom(src => src.Tag)); - CreateMap(); - - //-- APPLICANT HISTORY - CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap(); - CreateMap(); - CreateMap(); - - //-- PROJECT INFO - CreateMap() - .IgnoreNullAndDefaultValues(); - - //-- APPLICANT INFO - OUTBOUND MAPS - CreateMap(); - CreateMap(); - CreateMap() - .ForMember(dest => dest.IndigenousOrgInd, - opt => opt.MapFrom(src => src.IndigenousOrgInd != null ? ConvertIndigenousOrgIndToBool(src.IndigenousOrgInd) : null)); - CreateMap(); - CreateMap(); - - //-- APPLICANT INFO - INBOUND MAPS - CreateMap() - .IgnoreNullAndDefaultValues(); - CreateMap() - .IgnoreNullAndDefaultValues() - .ForMember(dest => dest.ElectoralDistrict, opt => opt.Ignore()); // Electoral district is handled separately - CreateMap() - .IgnoreNullAndDefaultValues(); - CreateMap() - .ForMember(dest => dest.IndigenousOrgInd, - opt => opt.MapFrom(src => ConvertBoolToIndigenousOrgInd(src.IndigenousOrgInd))) - .ForMember(dest => dest.RedStop, opt => opt.Ignore()) - .IgnoreNullAndDefaultValues(); - CreateMap() - .IgnoreNullAndDefaultValues(); - CreateMap() - .ForMember(dest => dest.Postal, opt => opt.MapFrom(src => src.PostalCode)) - .IgnoreNullAndDefaultValues(); - - } - - private static bool? ConvertIndigenousOrgIndToBool(string indigenousOrgInd) - { - return indigenousOrgInd switch - { - "Yes" => true, - "No" => false, - _ => null - }; - } - - private static string? ConvertBoolToIndigenousOrgInd(bool? indigenousOrgInd) - { - return indigenousOrgInd switch - { - true => "Yes", - false => "No", - _ => null - }; - } - -} - -// Extension methods for reusable mapping configurations -public static class MappingExtensions -{ - /// - /// Configures the mapping to ignore null and default values for all members. - /// Useful for patch/update scenarios where only non-default values should be mapped. - /// - /// The source type. - /// The destination type. - /// The mapping expression. - /// The updated mapping expression. - public static IMappingExpression IgnoreNullAndDefaultValues( - this IMappingExpression expression) - { - expression.ForAllMembers(opts => - { - opts.AllowNull(); // Ignore Null Values for Lists and Collections - opts.Condition((src, dest, srcMember) => - srcMember != null && !IsValueDefault(srcMember)); // Ignore Null and Default Values for Properties - }); - - return expression; - } - - /// - /// Determines whether the provided value is the default value for its type. - /// - /// The value to check. - /// - /// true if the value is null or the default for its type; otherwise, false. - /// - public static bool IsValueDefault(object value) - { - if (value == null) - return true; - - Type type = value.GetType(); - // For reference types, null is the only default - if (!type.IsValueType) - return false; - - // For value types, compare with default instance - return value.Equals(Activator.CreateInstance(type)); - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs new file mode 100644 index 0000000000..3539730fa7 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationMapperlyProfile.cs @@ -0,0 +1,1058 @@ +using Riok.Mapperly.Abstractions; +using System; +using System.Reflection; +using Unity.GrantManager.ApplicantProfile; +using Unity.GrantManager.ApplicationForms; +using Unity.GrantManager.Applications; +using Unity.GrantManager.Assessments; +using Unity.GrantManager.Attachments; +using Unity.GrantManager.Comments; +using Unity.GrantManager.Events; +using Unity.GrantManager.Forms; +using Unity.GrantManager.GlobalTag; +using Unity.GrantManager.GrantApplications; +using Unity.GrantManager.Identity; +using Unity.GrantManager.Intakes; +using Unity.GrantManager.Integrations; +using Unity.GrantManager.Locality; +using Unity.GrantManager.Zones; +using Unity.Payments.Domain.AccountCodings; +using Unity.Payments.PaymentRequests; +using Volo.Abp.Mapperly; + +namespace Unity.GrantManager; + +// --------------------------------------------------------------------------- +// Direct (forward) mappers — equivalent to AutoMapper CreateMap(). +// --------------------------------------------------------------------------- + +[Mapper] +public partial class CreateUpdateDynamicUrlDtoToDynamicUrlMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(DynamicUrl.Id))] + [MapperIgnoreTarget(nameof(DynamicUrl.TenantId))] + [MapperIgnoreTarget(nameof(DynamicUrl.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(DynamicUrl.IsDeleted))] + [MapperIgnoreTarget(nameof(DynamicUrl.DeleterId))] + [MapperIgnoreTarget(nameof(DynamicUrl.DeletionTime))] + [MapperIgnoreTarget(nameof(DynamicUrl.LastModificationTime))] + [MapperIgnoreTarget(nameof(DynamicUrl.LastModifierId))] + [MapperIgnoreTarget(nameof(DynamicUrl.CreationTime))] + [MapperIgnoreTarget(nameof(DynamicUrl.CreatorId))] + public override partial DynamicUrl Map(CreateUpdateDynamicUrlDto source); + + [MapperIgnoreTarget(nameof(DynamicUrl.Id))] + [MapperIgnoreTarget(nameof(DynamicUrl.TenantId))] + [MapperIgnoreTarget(nameof(DynamicUrl.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(DynamicUrl.IsDeleted))] + [MapperIgnoreTarget(nameof(DynamicUrl.DeleterId))] + [MapperIgnoreTarget(nameof(DynamicUrl.DeletionTime))] + [MapperIgnoreTarget(nameof(DynamicUrl.LastModificationTime))] + [MapperIgnoreTarget(nameof(DynamicUrl.LastModifierId))] + [MapperIgnoreTarget(nameof(DynamicUrl.CreationTime))] + [MapperIgnoreTarget(nameof(DynamicUrl.CreatorId))] + public override partial void Map(CreateUpdateDynamicUrlDto source, DynamicUrl destination); +} + +[Mapper] +public partial class CreateUpdateDynamicUrlDtoToDynamicUrlDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(DynamicUrlDto.Id))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.TenantId))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.CreationTime))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.CreatorId))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.LastModificationTime))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.LastModifierId))] + public override partial DynamicUrlDto Map(CreateUpdateDynamicUrlDto source); + + [MapperIgnoreTarget(nameof(DynamicUrlDto.Id))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.TenantId))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.CreationTime))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.CreatorId))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.LastModificationTime))] + [MapperIgnoreTarget(nameof(DynamicUrlDto.LastModifierId))] + public override partial void Map(CreateUpdateDynamicUrlDto source, DynamicUrlDto destination); +} + +[Mapper] +public partial class DynamicUrlDtoToCreateUpdateDynamicUrlDtoMapper : MapperBase +{ public override partial CreateUpdateDynamicUrlDto Map(DynamicUrlDto source); public override partial void Map(DynamicUrlDto source, CreateUpdateDynamicUrlDto destination); } + +[Mapper] +public partial class DynamicUrlToDynamicUrlDtoMapper : MapperBase +{ public override partial DynamicUrlDto Map(DynamicUrl source); public override partial void Map(DynamicUrl source, DynamicUrlDto destination); } + +[Mapper] +public partial class DynamicUrlToCreateUpdateDynamicUrlDtoMapper : MapperBase +{ public override partial CreateUpdateDynamicUrlDto Map(DynamicUrl source); public override partial void Map(DynamicUrl source, CreateUpdateDynamicUrlDto destination); } + +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ApplicationToGrantApplicationDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(GrantApplicationDto.RowCount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Assignees))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Status))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Probability))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Category))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.EconomicRegion))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.City))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.TotalProjectBudget))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Sector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubSector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ProjectSummary))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.TotalScore))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.RecommendedAmount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApprovedAmount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.LikelihoodOfFunding))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.DueDiligenceStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubStatusDisplayValue))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.DeclineRational))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Notes))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.StatusCode))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactFullName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactTitle))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactEmail))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactBusinessPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactCellPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationTag))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.NonRegOrgName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationType))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.BusinessNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationSize))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SectorSubSectorIndustryDesc))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.PaymentInfo))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.AIAnalysisData))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Owner))] + public override partial GrantApplicationDto Map(Application source); + + [MapperIgnoreTarget(nameof(GrantApplicationDto.RowCount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Assignees))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Status))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Probability))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Category))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.EconomicRegion))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.City))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.TotalProjectBudget))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Sector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubSector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ProjectSummary))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.TotalScore))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.RecommendedAmount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApprovedAmount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.LikelihoodOfFunding))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.DueDiligenceStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubStatusDisplayValue))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.DeclineRational))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Notes))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.StatusCode))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactFullName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactTitle))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactEmail))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactBusinessPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactCellPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationTag))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.NonRegOrgName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationType))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.BusinessNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationSize))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SectorSubSectorIndustryDesc))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.PaymentInfo))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.AIAnalysisData))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Owner))] + public override partial void Map(Application source, GrantApplicationDto destination); + + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.SiteId))] + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.ElectoralDistrict))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.FiscalDay), Use = nameof(ResolveFiscalDay))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.SupplierId), Use = nameof(ResolveApplicantSupplierId))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.RedStop), Use = nameof(ResolveApplicantRedStop))] + private partial GrantApplicationApplicantDto ToDto(Applicant source); + + [MapperIgnoreTarget(nameof(ApplicationFormDto.ChefsFormVersionGuid))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.SubmissionHeaderMapping))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.ApiToken))] + private partial ApplicationFormDto ToDto(ApplicationForm source); + + private static string ResolveFiscalDay(Applicant src) => src.FiscalDay?.ToString() ?? string.Empty; + private static Guid ResolveApplicantSupplierId(Applicant src) => src.SupplierId ?? Guid.Empty; + private static bool ResolveApplicantRedStop(Applicant src) => src.RedStop ?? false; +} +[Mapper] +public partial class ApplicationAssignmentToGrantApplicationAssigneeDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.FullName))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Email))] + public override partial GrantApplicationAssigneeDto Map(ApplicationAssignment source); + + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.FullName))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Email))] + public override partial void Map(ApplicationAssignment source, GrantApplicationAssigneeDto destination); +} + +[Mapper] +public partial class PersonToGrantApplicationAssigneeDtoMapper : MapperBase +{ + [MapProperty(nameof(Person.Id), nameof(GrantApplicationAssigneeDto.AssigneeId))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.ApplicationId))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Duty))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Email))] + public override partial GrantApplicationAssigneeDto Map(Person source); + + [MapProperty(nameof(Person.Id), nameof(GrantApplicationAssigneeDto.AssigneeId))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.ApplicationId))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Duty))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Email))] + public override partial void Map(Person source, GrantApplicationAssigneeDto destination); +} + +[Mapper] public partial class ApplicationStatusToApplicationStatusDtoMapper : MapperBase { public override partial ApplicationStatusDto Map(ApplicationStatus source); public override partial void Map(ApplicationStatus source, ApplicationStatusDto destination); } + +[Mapper] +public partial class AssessmentCommentToCommentDtoMapper : MapperBase +{ + [MapProperty(nameof(AssessmentComment.AssessmentId), nameof(CommentDto.OwnerId))] + [MapperIgnoreTarget(nameof(CommentDto.Badge))] + [MapperIgnoreTarget(nameof(CommentDto.Commenter))] + public override partial CommentDto Map(AssessmentComment source); + + [MapProperty(nameof(AssessmentComment.AssessmentId), nameof(CommentDto.OwnerId))] + [MapperIgnoreTarget(nameof(CommentDto.Badge))] + [MapperIgnoreTarget(nameof(CommentDto.Commenter))] + public override partial void Map(AssessmentComment source, CommentDto destination); +} + +[Mapper] +public partial class ApplicationCommentToCommentDtoMapper : MapperBase +{ + [MapProperty(nameof(ApplicationComment.ApplicationId), nameof(CommentDto.OwnerId))] + [MapperIgnoreTarget(nameof(CommentDto.Badge))] + [MapperIgnoreTarget(nameof(CommentDto.Commenter))] + public override partial CommentDto Map(ApplicationComment source); + + [MapProperty(nameof(ApplicationComment.ApplicationId), nameof(CommentDto.OwnerId))] + [MapperIgnoreTarget(nameof(CommentDto.Badge))] + [MapperIgnoreTarget(nameof(CommentDto.Commenter))] + public override partial void Map(ApplicationComment source, CommentDto destination); +} + +[Mapper] +public partial class ApplicantCommentToCommentDtoMapper : MapperBase +{ + [MapProperty(nameof(ApplicantComment.ApplicantId), nameof(CommentDto.OwnerId))] + [MapperIgnoreTarget(nameof(CommentDto.Badge))] + [MapperIgnoreTarget(nameof(CommentDto.Commenter))] + public override partial CommentDto Map(ApplicantComment source); + + [MapProperty(nameof(ApplicantComment.ApplicantId), nameof(CommentDto.OwnerId))] + [MapperIgnoreTarget(nameof(CommentDto.Badge))] + [MapperIgnoreTarget(nameof(CommentDto.Commenter))] + public override partial void Map(ApplicantComment source, CommentDto destination); +} + +public class CommentBaseToCommentDtoMapper : MapperBase +{ + public override CommentDto Map(CommentBase source) => source switch + { + ApplicationComment a => new ApplicationCommentToCommentDtoMapper().Map(a), + AssessmentComment a => new AssessmentCommentToCommentDtoMapper().Map(a), + ApplicantComment a => new ApplicantCommentToCommentDtoMapper().Map(a), + _ => throw new System.NotSupportedException($"Unsupported comment type: {source.GetType().FullName}") + }; + + public override void Map(CommentBase source, CommentDto destination) + { + switch (source) + { + case ApplicationComment a: new ApplicationCommentToCommentDtoMapper().Map(a, destination); break; + case AssessmentComment a: new AssessmentCommentToCommentDtoMapper().Map(a, destination); break; + case ApplicantComment a: new ApplicantCommentToCommentDtoMapper().Map(a, destination); break; + default: throw new System.NotSupportedException($"Unsupported comment type: {source.GetType().FullName}"); + } + } +} + +[Mapper] +public partial class CommentListItemToCommentDtoMapper : MapperBase +{ + [MapProperty(nameof(CommentListItem.CommenterBadge), nameof(CommentDto.Badge))] + [MapProperty(nameof(CommentListItem.CommenterDisplayName), nameof(CommentDto.Commenter))] + public override partial CommentDto Map(CommentListItem source); + + [MapProperty(nameof(CommentListItem.CommenterBadge), nameof(CommentDto.Badge))] + [MapProperty(nameof(CommentListItem.CommenterDisplayName), nameof(CommentDto.Commenter))] + public override partial void Map(CommentListItem source, CommentDto destination); +} + +[Mapper] +public partial class AssessmentToAssessmentDtoMapper : MapperBase +{ + [MapProperty(nameof(Assessment.CreationTime), nameof(AssessmentDto.StartDate))] + public override partial AssessmentDto Map(Assessment source); + + [MapProperty(nameof(Assessment.CreationTime), nameof(AssessmentDto.StartDate))] + public override partial void Map(Assessment source, AssessmentDto destination); +} + +[Mapper] +public partial class AssessmentWithAssessorQueryResultItemToAssessmentListItemDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(AssessmentListItemDto.SubTotal))] + public override partial AssessmentListItemDto Map(AssessmentWithAssessorQueryResultItem source); + + [MapperIgnoreTarget(nameof(AssessmentListItemDto.SubTotal))] + public override partial void Map(AssessmentWithAssessorQueryResultItem source, AssessmentListItemDto destination); +} + +[Mapper] +public partial class ApplicationChefsFileAttachmentToDtoMapper : MapperBase +{ + [MapProperty(nameof(ApplicationChefsFileAttachment.CreationTime), nameof(ApplicationChefsFileAttachmentDto.CreatedTime))] + [MapProperty(nameof(ApplicationChefsFileAttachment.LastModificationTime), nameof(ApplicationChefsFileAttachmentDto.UpdatedTime))] + [MapperIgnoreTarget(nameof(ApplicationChefsFileAttachmentDto.Name))] + public override partial ApplicationChefsFileAttachmentDto Map(ApplicationChefsFileAttachment source); + + [MapProperty(nameof(ApplicationChefsFileAttachment.CreationTime), nameof(ApplicationChefsFileAttachmentDto.CreatedTime))] + [MapProperty(nameof(ApplicationChefsFileAttachment.LastModificationTime), nameof(ApplicationChefsFileAttachmentDto.UpdatedTime))] + [MapperIgnoreTarget(nameof(ApplicationChefsFileAttachmentDto.Name))] + public override partial void Map(ApplicationChefsFileAttachment source, ApplicationChefsFileAttachmentDto destination); +} + +[Mapper] +public partial class ApplicationAttachmentToDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationAttachmentDto.AttachedBy))] + public override partial ApplicationAttachmentDto Map(ApplicationAttachment source); + + [MapperIgnoreTarget(nameof(ApplicationAttachmentDto.AttachedBy))] + public override partial void Map(ApplicationAttachment source, ApplicationAttachmentDto destination); +} +[Mapper] public partial class IntakeToIntakeDtoMapper : MapperBase { public override partial IntakeDto Map(Intakes.Intake source); public override partial void Map(Intakes.Intake source, IntakeDto destination); } +[Mapper] +public partial class ApplicationFormToDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationFormDto.ChefsFormVersionGuid))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.SubmissionHeaderMapping))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.ApiToken))] + public override partial ApplicationFormDto Map(ApplicationForm source); + + [MapperIgnoreTarget(nameof(ApplicationFormDto.ChefsFormVersionGuid))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.SubmissionHeaderMapping))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.ApiToken))] + public override partial void Map(ApplicationForm source, ApplicationFormDto destination); +} +[Mapper] +public partial class ApplicationFormDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationForm.DeleterId))] + [MapperIgnoreTarget(nameof(ApplicationForm.DeletionTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationForm.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(ApplicationForm.FormHierarchy))] + [MapperIgnoreTarget(nameof(ApplicationForm.ParentFormId))] + [MapperIgnoreTarget(nameof(ApplicationForm.IsDeleted))] + [MapperIgnoreTarget(nameof(ApplicationForm.PaymentApprovalThreshold))] + public override partial ApplicationForm Map(ApplicationFormDto source); + + [MapperIgnoreTarget(nameof(ApplicationForm.DeleterId))] + [MapperIgnoreTarget(nameof(ApplicationForm.DeletionTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationForm.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(ApplicationForm.FormHierarchy))] + [MapperIgnoreTarget(nameof(ApplicationForm.ParentFormId))] + [MapperIgnoreTarget(nameof(ApplicationForm.IsDeleted))] + [MapperIgnoreTarget(nameof(ApplicationForm.PaymentApprovalThreshold))] + public override partial void Map(ApplicationFormDto source, ApplicationForm destination); +} +[Mapper] public partial class ApplicationFormVersionToDtoMapper : MapperBase { public override partial ApplicationFormVersionDto Map(ApplicationFormVersion source); public override partial void Map(ApplicationFormVersion source, ApplicationFormVersionDto destination); } +[Mapper] +public partial class ApplicationFormVersionDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationFormVersion.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ConcurrencyStamp))] + public override partial ApplicationFormVersion Map(ApplicationFormVersionDto source); + + [MapperIgnoreTarget(nameof(ApplicationFormVersion.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ConcurrencyStamp))] + public override partial void Map(ApplicationFormVersionDto source, ApplicationFormVersion destination); +} +[Mapper] +public partial class CreateUpdateApplicationFormVersionDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationFormVersion.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ReportColumns))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ReportKeys))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ReportViewName))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.FormSchema))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ConcurrencyStamp))] + public override partial ApplicationFormVersion Map(CreateUpdateApplicationFormVersionDto source); + + [MapperIgnoreTarget(nameof(ApplicationFormVersion.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ReportColumns))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ReportKeys))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ReportViewName))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.FormSchema))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationFormVersion.ConcurrencyStamp))] + public override partial void Map(CreateUpdateApplicationFormVersionDto source, ApplicationFormVersion destination); +} +[Mapper] +public partial class CreateUpdateIntakeDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(Intakes.Intake.TenantId))] + [MapperIgnoreTarget(nameof(Intakes.Intake.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(Intakes.Intake.IsDeleted))] + [MapperIgnoreTarget(nameof(Intakes.Intake.DeleterId))] + [MapperIgnoreTarget(nameof(Intakes.Intake.DeletionTime))] + [MapperIgnoreTarget(nameof(Intakes.Intake.LastModificationTime))] + [MapperIgnoreTarget(nameof(Intakes.Intake.LastModifierId))] + [MapperIgnoreTarget(nameof(Intakes.Intake.CreationTime))] + [MapperIgnoreTarget(nameof(Intakes.Intake.CreatorId))] + public override partial Intakes.Intake Map(CreateUpdateIntakeDto source); + + [MapperIgnoreTarget(nameof(Intakes.Intake.TenantId))] + [MapperIgnoreTarget(nameof(Intakes.Intake.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(Intakes.Intake.IsDeleted))] + [MapperIgnoreTarget(nameof(Intakes.Intake.DeleterId))] + [MapperIgnoreTarget(nameof(Intakes.Intake.DeletionTime))] + [MapperIgnoreTarget(nameof(Intakes.Intake.LastModificationTime))] + [MapperIgnoreTarget(nameof(Intakes.Intake.LastModifierId))] + [MapperIgnoreTarget(nameof(Intakes.Intake.CreationTime))] + [MapperIgnoreTarget(nameof(Intakes.Intake.CreatorId))] + public override partial void Map(CreateUpdateIntakeDto source, Intakes.Intake destination); +} +[Mapper] +public partial class CreateUpdateApplicationFormDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationForm.AvailableChefsFields))] + [MapperIgnoreTarget(nameof(ApplicationForm.ConnectionHttpStatus))] + [MapperIgnoreTarget(nameof(ApplicationForm.AttemptedConnectionDate))] + [MapperIgnoreTarget(nameof(ApplicationForm.PreventPayment))] + [MapperIgnoreTarget(nameof(ApplicationForm.AccountCodingId))] + [MapperIgnoreTarget(nameof(ApplicationForm.ScoresheetId))] + [MapperIgnoreTarget(nameof(ApplicationForm.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationForm.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(ApplicationForm.IsDeleted))] + [MapperIgnoreTarget(nameof(ApplicationForm.DeleterId))] + [MapperIgnoreTarget(nameof(ApplicationForm.DeletionTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationForm.PaymentApprovalThreshold))] + [MapperIgnoreTarget(nameof(ApplicationForm.DefaultPaymentGroup))] + [MapperIgnoreTarget(nameof(ApplicationForm.FormHierarchy))] + [MapperIgnoreTarget(nameof(ApplicationForm.ParentFormId))] + [MapperIgnoreTarget(nameof(ApplicationForm.IsDirectApproval))] + [MapperIgnoreTarget(nameof(ApplicationForm.AutomaticallyGenerateAIAnalysis))] + [MapperIgnoreTarget(nameof(ApplicationForm.ManuallyInitiateAIAnalysis))] + [MapperIgnoreTarget(nameof(ApplicationForm.Prefix))] + [MapperIgnoreTarget(nameof(ApplicationForm.SuffixType))] + [MapperIgnoreTarget(nameof(ApplicationForm.ElectoralDistrictAddressType))] + public override partial ApplicationForm Map(CreateUpdateApplicationFormDto source); + + [MapperIgnoreTarget(nameof(ApplicationForm.AvailableChefsFields))] + [MapperIgnoreTarget(nameof(ApplicationForm.ConnectionHttpStatus))] + [MapperIgnoreTarget(nameof(ApplicationForm.AttemptedConnectionDate))] + [MapperIgnoreTarget(nameof(ApplicationForm.PreventPayment))] + [MapperIgnoreTarget(nameof(ApplicationForm.AccountCodingId))] + [MapperIgnoreTarget(nameof(ApplicationForm.ScoresheetId))] + [MapperIgnoreTarget(nameof(ApplicationForm.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationForm.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(ApplicationForm.IsDeleted))] + [MapperIgnoreTarget(nameof(ApplicationForm.DeleterId))] + [MapperIgnoreTarget(nameof(ApplicationForm.DeletionTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationForm.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationForm.PaymentApprovalThreshold))] + [MapperIgnoreTarget(nameof(ApplicationForm.DefaultPaymentGroup))] + [MapperIgnoreTarget(nameof(ApplicationForm.FormHierarchy))] + [MapperIgnoreTarget(nameof(ApplicationForm.ParentFormId))] + [MapperIgnoreTarget(nameof(ApplicationForm.IsDirectApproval))] + [MapperIgnoreTarget(nameof(ApplicationForm.AutomaticallyGenerateAIAnalysis))] + [MapperIgnoreTarget(nameof(ApplicationForm.ManuallyInitiateAIAnalysis))] + [MapperIgnoreTarget(nameof(ApplicationForm.Prefix))] + [MapperIgnoreTarget(nameof(ApplicationForm.SuffixType))] + [MapperIgnoreTarget(nameof(ApplicationForm.ElectoralDistrictAddressType))] + public override partial void Map(CreateUpdateApplicationFormDto source, ApplicationForm destination); +} +[Mapper] +public partial class AssessmentAttachmentToDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(AssessmentAttachmentDto.AttachedBy))] + public override partial AssessmentAttachmentDto Map(AssessmentAttachment source); + + [MapperIgnoreTarget(nameof(AssessmentAttachmentDto.AttachedBy))] + public override partial void Map(AssessmentAttachment source, AssessmentAttachmentDto destination); +} + +[Mapper] +public partial class ApplicationActionResultItemToDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationActionDto.IsAuthorized))] + public override partial ApplicationActionDto Map(ApplicationActionResultItem source); + + [MapperIgnoreTarget(nameof(ApplicationActionDto.IsAuthorized))] + public override partial void Map(ApplicationActionResultItem source, ApplicationActionDto destination); +} +[Mapper] public partial class EventSubscriptionToDtoMapper : MapperBase { public override partial EventSubscriptionDto Map(EventSubscription source); public override partial void Map(EventSubscription source, EventSubscriptionDto destination); } +[Mapper] public partial class EventSubscriptionDtoToEntityMapper : MapperBase { public override partial EventSubscription Map(EventSubscriptionDto source); public override partial void Map(EventSubscriptionDto source, EventSubscription destination); } +[Mapper] public partial class SectorToDtoMapper : MapperBase { public override partial SectorDto Map(Sector source); public override partial void Map(Sector source, SectorDto destination); } +[Mapper] public partial class SubSectorToDtoMapper : MapperBase { public override partial SubSectorDto Map(SubSector source); public override partial void Map(SubSector source, SubSectorDto destination); } +[Mapper] public partial class EconomicRegionToDtoMapper : MapperBase { public override partial EconomicRegionDto Map(EconomicRegion source); public override partial void Map(EconomicRegion source, EconomicRegionDto destination); } +[Mapper] public partial class ElectoralDistrictToDtoMapper : MapperBase { public override partial ElectoralDistrictDto Map(ElectoralDistrict source); public override partial void Map(ElectoralDistrict source, ElectoralDistrictDto destination); } +[Mapper] public partial class CommunityToDtoMapper : MapperBase { public override partial CommunityDto Map(Community source); public override partial void Map(Community source, CommunityDto destination); } +[Mapper] public partial class RegionalDistrictToDtoMapper : MapperBase { public override partial RegionalDistrictDto Map(RegionalDistrict source); public override partial void Map(RegionalDistrict source, RegionalDistrictDto destination); } +[Mapper] public partial class ApplicationTagsToDtoMapper : MapperBase { public override partial ApplicationTagsDto Map(ApplicationTags source); public override partial void Map(ApplicationTags source, ApplicationTagsDto destination); } +[Mapper] public partial class AIGenerationRequestToDtoMapper : MapperBase { public override partial AIGenerationRequestDto Map(AIGenerationRequest source); public override partial void Map(AIGenerationRequest source, AIGenerationRequestDto destination); } +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ApplicantToGrantApplicationApplicantDtoMapper : MapperBase +{ + [MapProperty(nameof(Applicant.Id), nameof(GrantApplicationApplicantDto.Id))] + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.SiteId))] + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.ElectoralDistrict))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.FiscalDay), Use = nameof(ResolveFiscalDay))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.SupplierId), Use = nameof(ResolveSupplierId))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.RedStop), Use = nameof(ResolveRedStop))] + public override partial GrantApplicationApplicantDto Map(Applicant source); + + [MapProperty(nameof(Applicant.Id), nameof(GrantApplicationApplicantDto.Id))] + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.SiteId))] + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.ElectoralDistrict))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.FiscalDay), Use = nameof(ResolveFiscalDay))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.SupplierId), Use = nameof(ResolveSupplierId))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.RedStop), Use = nameof(ResolveRedStop))] + public override partial void Map(Applicant source, GrantApplicationApplicantDto destination); + + private static string ResolveFiscalDay(Applicant src) => src.FiscalDay?.ToString() ?? string.Empty; + private static Guid ResolveSupplierId(Applicant src) => src.SupplierId ?? Guid.Empty; + private static bool ResolveRedStop(Applicant src) => src.RedStop ?? false; +} +[Mapper] public partial class ApplicationContactToDtoMapper : MapperBase { public override partial ApplicationContactDto Map(ApplicationContact source); public override partial void Map(ApplicationContact source, ApplicationContactDto destination); } +[Mapper] +public partial class ApplicationContactDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationContact.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationContact.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationContact.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationContact.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationContact.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationContact.ConcurrencyStamp))] + public override partial ApplicationContact Map(ApplicationContactDto source); + + [MapperIgnoreTarget(nameof(ApplicationContact.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationContact.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationContact.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationContact.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationContact.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationContact.ConcurrencyStamp))] + public override partial void Map(ApplicationContactDto source, ApplicationContact destination); +} +[Mapper] public partial class ApplicationLinkToDtoMapper : MapperBase { public override partial ApplicationLinksDto Map(ApplicationLink source); public override partial void Map(ApplicationLink source, ApplicationLinksDto destination); } +[Mapper] +public partial class ApplicationLinksDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicationLink.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationLink.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationLink.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationLink.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationLink.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationLink.ConcurrencyStamp))] + public override partial ApplicationLink Map(ApplicationLinksDto source); + + [MapperIgnoreTarget(nameof(ApplicationLink.TenantId))] + [MapperIgnoreTarget(nameof(ApplicationLink.CreationTime))] + [MapperIgnoreTarget(nameof(ApplicationLink.CreatorId))] + [MapperIgnoreTarget(nameof(ApplicationLink.LastModificationTime))] + [MapperIgnoreTarget(nameof(ApplicationLink.LastModifierId))] + [MapperIgnoreTarget(nameof(ApplicationLink.ConcurrencyStamp))] + public override partial void Map(ApplicationLinksDto source, ApplicationLink destination); +} +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ApplicationToGrantApplicationLiteDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(GrantApplicationLiteDto.ApplicantName))] + [MapperIgnoreTarget(nameof(GrantApplicationLiteDto.OrganizationName))] + [MapperIgnoreTarget(nameof(GrantApplicationLiteDto.UnityApplicantId))] + public override partial GrantApplicationLiteDto Map(Application source); + + [MapperIgnoreTarget(nameof(GrantApplicationLiteDto.ApplicantName))] + [MapperIgnoreTarget(nameof(GrantApplicationLiteDto.OrganizationName))] + [MapperIgnoreTarget(nameof(GrantApplicationLiteDto.UnityApplicantId))] + public override partial void Map(Application source, GrantApplicationLiteDto destination); +} +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ApplicantAddressToDtoMapper : MapperBase +{ + public override partial ApplicantAddressDto Map(ApplicantAddress source); + public override partial void Map(ApplicantAddress source, ApplicantAddressDto destination); +} +[Mapper] public partial class AccountCodingToAccountCodingDtoGmMapper : MapperBase { public override partial AccountCodingDto Map(AccountCoding source); public override partial void Map(AccountCoding source, AccountCodingDto destination); } +[Mapper] public partial class TagToDtoMapper : MapperBase { public override partial TagDto Map(Tag source); public override partial void Map(Tag source, TagDto destination); } +[Mapper] public partial class TagSummaryCountToDtoGmMapper : MapperBase { public override partial TagSummaryCountDto Map(TagSummaryCount source); public override partial void Map(TagSummaryCount source, TagSummaryCountDto destination); } +[Mapper] public partial class TagUsageSummaryToDtoMapper : MapperBase { public override partial TagUsageSummaryDto Map(TagUsageSummary source); public override partial void Map(TagUsageSummary source, TagUsageSummaryDto destination); } + +[Mapper] +public partial class FundingHistoryToDtoMapper : MapperBase +{ + public override partial FundingHistoryDto Map(FundingHistory source); + public override partial void Map(FundingHistory source, FundingHistoryDto destination); +} +[Mapper] +public partial class CreateUpdateFundingHistoryDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(FundingHistory.Id))] + [MapperIgnoreTarget(nameof(FundingHistory.TenantId))] + [MapperIgnoreTarget(nameof(FundingHistory.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(FundingHistory.CreationTime))] + [MapperIgnoreTarget(nameof(FundingHistory.CreatorId))] + [MapperIgnoreTarget(nameof(FundingHistory.LastModificationTime))] + [MapperIgnoreTarget(nameof(FundingHistory.LastModifierId))] + public override partial FundingHistory Map(CreateUpdateFundingHistoryDto source); + + [MapperIgnoreTarget(nameof(FundingHistory.Id))] + [MapperIgnoreTarget(nameof(FundingHistory.TenantId))] + [MapperIgnoreTarget(nameof(FundingHistory.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(FundingHistory.CreationTime))] + [MapperIgnoreTarget(nameof(FundingHistory.CreatorId))] + [MapperIgnoreTarget(nameof(FundingHistory.LastModificationTime))] + [MapperIgnoreTarget(nameof(FundingHistory.LastModifierId))] + public override partial void Map(CreateUpdateFundingHistoryDto source, FundingHistory destination); +} + +[Mapper] +public partial class FundingHistoryDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(FundingHistory.TenantId))] + [MapperIgnoreTarget(nameof(FundingHistory.ConcurrencyStamp))] + public override partial FundingHistory Map(FundingHistoryDto source); + + [MapperIgnoreTarget(nameof(FundingHistory.TenantId))] + [MapperIgnoreTarget(nameof(FundingHistory.ConcurrencyStamp))] + public override partial void Map(FundingHistoryDto source, FundingHistory destination); +} + +[Mapper] public partial class IssueTrackingToDtoMapper : MapperBase { public override partial IssueTrackingDto Map(IssueTracking source); public override partial void Map(IssueTracking source, IssueTrackingDto destination); } +[Mapper] +public partial class CreateUpdateIssueTrackingDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(IssueTracking.Id))] + [MapperIgnoreTarget(nameof(IssueTracking.TenantId))] + [MapperIgnoreTarget(nameof(IssueTracking.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(IssueTracking.CreationTime))] + [MapperIgnoreTarget(nameof(IssueTracking.CreatorId))] + [MapperIgnoreTarget(nameof(IssueTracking.LastModificationTime))] + [MapperIgnoreTarget(nameof(IssueTracking.LastModifierId))] + public override partial IssueTracking Map(CreateUpdateIssueTrackingDto source); + + [MapperIgnoreTarget(nameof(IssueTracking.Id))] + [MapperIgnoreTarget(nameof(IssueTracking.TenantId))] + [MapperIgnoreTarget(nameof(IssueTracking.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(IssueTracking.CreationTime))] + [MapperIgnoreTarget(nameof(IssueTracking.CreatorId))] + [MapperIgnoreTarget(nameof(IssueTracking.LastModificationTime))] + [MapperIgnoreTarget(nameof(IssueTracking.LastModifierId))] + public override partial void Map(CreateUpdateIssueTrackingDto source, IssueTracking destination); +} + +[Mapper] +public partial class IssueTrackingDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(IssueTracking.TenantId))] + [MapperIgnoreTarget(nameof(IssueTracking.ConcurrencyStamp))] + public override partial IssueTracking Map(IssueTrackingDto source); + + [MapperIgnoreTarget(nameof(IssueTracking.TenantId))] + [MapperIgnoreTarget(nameof(IssueTracking.ConcurrencyStamp))] + public override partial void Map(IssueTrackingDto source, IssueTracking destination); +} + +[Mapper] public partial class AuditHistoryToDtoMapper : MapperBase { public override partial AuditHistoryDto Map(AuditHistory source); public override partial void Map(AuditHistory source, AuditHistoryDto destination); } +[Mapper] +public partial class CreateUpdateAuditHistoryDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(AuditHistory.Id))] + [MapperIgnoreTarget(nameof(AuditHistory.TenantId))] + [MapperIgnoreTarget(nameof(AuditHistory.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(AuditHistory.CreationTime))] + [MapperIgnoreTarget(nameof(AuditHistory.CreatorId))] + [MapperIgnoreTarget(nameof(AuditHistory.LastModificationTime))] + [MapperIgnoreTarget(nameof(AuditHistory.LastModifierId))] + public override partial AuditHistory Map(CreateUpdateAuditHistoryDto source); + + [MapperIgnoreTarget(nameof(AuditHistory.Id))] + [MapperIgnoreTarget(nameof(AuditHistory.TenantId))] + [MapperIgnoreTarget(nameof(AuditHistory.ConcurrencyStamp))] + [MapperIgnoreTarget(nameof(AuditHistory.CreationTime))] + [MapperIgnoreTarget(nameof(AuditHistory.CreatorId))] + [MapperIgnoreTarget(nameof(AuditHistory.LastModificationTime))] + [MapperIgnoreTarget(nameof(AuditHistory.LastModifierId))] + public override partial void Map(CreateUpdateAuditHistoryDto source, AuditHistory destination); +} + +[Mapper] +public partial class AuditHistoryDtoToEntityMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(AuditHistory.TenantId))] + [MapperIgnoreTarget(nameof(AuditHistory.ConcurrencyStamp))] + public override partial AuditHistory Map(AuditHistoryDto source); + + [MapperIgnoreTarget(nameof(AuditHistory.TenantId))] + [MapperIgnoreTarget(nameof(AuditHistory.ConcurrencyStamp))] + public override partial void Map(AuditHistoryDto source, AuditHistory destination); +} + +[Mapper] +public partial class ApplicationToApplicantInfoDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicantName))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicationStatusCode))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicantSummary))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.SigningAuthority))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ContactInfo))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicationId))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicationReferenceNo))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.CustomFields))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.CorrelationId))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.WorksheetId))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.WorksheetIds))] + public override partial ApplicantInfoDto Map(Application source); + + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicantName))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicationStatusCode))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicantSummary))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.SigningAuthority))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ContactInfo))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicationId))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.ApplicationReferenceNo))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.CustomFields))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.CorrelationId))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.WorksheetId))] + [MapperIgnoreTarget(nameof(ApplicantInfoDto.WorksheetIds))] + public override partial void Map(Application source, ApplicantInfoDto destination); +} + +[Mapper] +public partial class ApplicationToSigningAuthorityDtoMapper : MapperBase +{ + public override partial SigningAuthorityDto Map(Application source); + public override partial void Map(Application source, SigningAuthorityDto destination); +} + +[Mapper] +public partial class ApplicantAgentToContactInfoDtoMapper : MapperBase +{ + [MapProperty("Id", nameof(ContactInfoDto.ApplicantAgentId))] + public override partial ContactInfoDto Map(ApplicantAgent source); + + [MapProperty("Id", nameof(ContactInfoDto.ApplicantAgentId))] + public override partial void Map(ApplicantAgent source, ContactInfoDto destination); +} + +[Mapper] +public partial class ApplicantToApplicantSummaryDtoMapper : MapperBase +{ + [MapProperty("Id", nameof(ApplicantSummaryDto.ApplicantId))] + [MapperIgnoreTarget(nameof(ApplicantSummaryDto.ElectoralDistrict))] + [MapPropertyFromSource(nameof(ApplicantSummaryDto.FiscalDay), Use = nameof(ResolveFiscalDay))] + public override partial ApplicantSummaryDto Map(Applicant source); + + [MapProperty("Id", nameof(ApplicantSummaryDto.ApplicantId))] + [MapperIgnoreTarget(nameof(ApplicantSummaryDto.ElectoralDistrict))] + [MapPropertyFromSource(nameof(ApplicantSummaryDto.FiscalDay), Use = nameof(ResolveFiscalDay))] + public override partial void Map(Applicant source, ApplicantSummaryDto destination); + + private static bool? MapIndigenousOrgInd(string? value) => GrantManagerMapperlyHelpers.IndigenousOrgIndToBool(value); + private static string? ResolveFiscalDay(Applicant src) => src.FiscalDay?.ToString(); +} + +// --------------------------------------------------------------------------- +// Two-way mappers (CreateMap<...>().ReverseMap()). +// --------------------------------------------------------------------------- + +[Mapper] +public partial class ZoneGroupDefinitionMapper : TwoWayMapperBase +{ + public override partial ZoneGroupDefinitionDto Map(ZoneGroupDefinition source); + public override partial void Map(ZoneGroupDefinition source, ZoneGroupDefinitionDto destination); + public override partial ZoneGroupDefinition ReverseMap(ZoneGroupDefinitionDto source); + public override partial void ReverseMap(ZoneGroupDefinitionDto source, ZoneGroupDefinition destination); + + // Forward nested: ZoneTabDefinition → ZoneTabDefinitionDto (used for Tabs collection) + private partial ZoneTabDefinitionDto MapTabDto(ZoneTabDefinition source); + + // Reverse nested: ZoneTabDefinitionDto → ZoneTabDefinition (ignore DisplayName missing from DTO) + [MapperIgnoreTarget(nameof(ZoneTabDefinition.DisplayName))] + private partial ZoneTabDefinition MapTab(ZoneTabDefinitionDto source); + + // Forward nested: ZoneDefinition → ZoneDefinitionDto (ignore Arguments missing from entity) + [MapperIgnoreTarget(nameof(ZoneDefinitionDto.Arguments))] + private partial ZoneDefinitionDto MapZoneDto(ZoneDefinition source); +} + +[Mapper] +public partial class ZoneTabDefinitionMapper : TwoWayMapperBase +{ + public override partial ZoneTabDefinitionDto Map(ZoneTabDefinition source); + public override partial void Map(ZoneTabDefinition source, ZoneTabDefinitionDto destination); + + [MapperIgnoreTarget(nameof(ZoneTabDefinition.DisplayName))] + public override partial ZoneTabDefinition ReverseMap(ZoneTabDefinitionDto source); + + [MapperIgnoreTarget(nameof(ZoneTabDefinition.DisplayName))] + public override partial void ReverseMap(ZoneTabDefinitionDto source, ZoneTabDefinition destination); + + // Forward nested: ZoneDefinition → ZoneDefinitionDto (ignore Arguments missing from entity) + [MapperIgnoreTarget(nameof(ZoneDefinitionDto.Arguments))] + private partial ZoneDefinitionDto MapZoneDto(ZoneDefinition source); +} + +[Mapper] +public partial class ZoneDefinitionMapper : TwoWayMapperBase +{ + [MapperIgnoreTarget(nameof(ZoneDefinitionDto.Arguments))] + public override partial ZoneDefinitionDto Map(ZoneDefinition source); + + [MapperIgnoreTarget(nameof(ZoneDefinitionDto.Arguments))] + public override partial void Map(ZoneDefinition source, ZoneDefinitionDto destination); + + public override partial ZoneDefinition ReverseMap(ZoneDefinitionDto source); + public override partial void ReverseMap(ZoneDefinitionDto source, ZoneDefinition destination); +} + +// --------------------------------------------------------------------------- +// Patch mappers — preserve AutoMapper's IgnoreNullAndDefaultValues semantics: +// only non-null, non-default source members overwrite the destination. +// --------------------------------------------------------------------------- + +public class UpdateProjectInfoDtoToApplicationMapper : MapperBase +{ + public override Application Map(UpdateProjectInfoDto source) + { + var destination = new Application(); + Map(source, destination); + return destination; + } + + public override void Map(UpdateProjectInfoDto source, Application destination) + => GrantManagerMapperlyHelpers.CopyNonDefault(source, destination); +} + +public class UpdateApplicantInfoDtoToApplicantMapper : MapperBase +{ + public override Applicant Map(UpdateApplicantInfoDto source) + { + var destination = new Applicant(); + Map(source, destination); + return destination; + } + + public override void Map(UpdateApplicantInfoDto source, Applicant destination) + => GrantManagerMapperlyHelpers.CopyNonDefault(source, destination); +} + +public class UpdateApplicantInfoDtoToApplicationMapper : MapperBase +{ + private static readonly string[] IgnoredMembers = [nameof(Application.ElectoralDistrict)]; + + public override Application Map(UpdateApplicantInfoDto source) + { + var destination = new Application(); + Map(source, destination); + return destination; + } + + public override void Map(UpdateApplicantInfoDto source, Application destination) + => GrantManagerMapperlyHelpers.CopyNonDefault(source, destination, IgnoredMembers); +} + +public class SigningAuthorityDtoToApplicationMapper : MapperBase +{ + public override Application Map(SigningAuthorityDto source) + { + var destination = new Application(); + Map(source, destination); + return destination; + } + + public override void Map(SigningAuthorityDto source, Application destination) + => GrantManagerMapperlyHelpers.CopyNonDefault(source, destination); +} + +public class UpdateApplicantSummaryDtoToApplicantMapper : MapperBase +{ + private static readonly string[] IgnoredMembers = [nameof(Applicant.RedStop), nameof(Applicant.IndigenousOrgInd)]; + + public override Applicant Map(UpdateApplicantSummaryDto source) + { + var destination = new Applicant(); + Map(source, destination); + return destination; + } + + public override void Map(UpdateApplicantSummaryDto source, Applicant destination) + { + GrantManagerMapperlyHelpers.CopyNonDefault(source, destination, IgnoredMembers); + + // IndigenousOrgInd: bool? -> "Yes"/"No"/null. Always apply unless the + // source value itself is the default (null) — matches AutoMapper. + if (source.IndigenousOrgInd != null) + { + destination.IndigenousOrgInd = GrantManagerMapperlyHelpers.BoolToIndigenousOrgInd(source.IndigenousOrgInd); + } + } +} + +public class ContactInfoDtoToApplicantAgentMapper : MapperBase +{ + public override ApplicantAgent Map(ContactInfoDto source) + { + var destination = new ApplicantAgent(); + Map(source, destination); + return destination; + } + + public override void Map(ContactInfoDto source, ApplicantAgent destination) + => GrantManagerMapperlyHelpers.CopyNonDefault(source, destination); +} + +public class UpdateApplicantAddressDtoToApplicantAddressMapper : MapperBase +{ + private static readonly string[] IgnoredMembers = [nameof(ApplicantAddress.Postal)]; + + public override ApplicantAddress Map(UpdateApplicantAddressDto source) + { + var destination = new ApplicantAddress(); + Map(source, destination); + return destination; + } + + public override void Map(UpdateApplicantAddressDto source, ApplicantAddress destination) + { + GrantManagerMapperlyHelpers.CopyNonDefault(source, destination, IgnoredMembers); + + // Map PostalCode -> Postal when the source actually has a value. + if (!string.IsNullOrEmpty(source.PostalCode)) + { + destination.Postal = source.PostalCode; + } + } +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +internal static class GrantManagerMapperlyHelpers +{ + public static bool? IndigenousOrgIndToBool(string? indigenousOrgInd) => indigenousOrgInd switch + { + "Yes" => true, + "No" => false, + _ => null, + }; + + public static string? BoolToIndigenousOrgInd(bool? indigenousOrgInd) => indigenousOrgInd switch + { + true => "Yes", + false => "No", + _ => null, + }; + + /// + /// Copies all readable members of whose value is not null + /// and not the default for their type onto matching writable members of + /// . Mirrors the behavior of AutoMapper's + /// IgnoreNullAndDefaultValues extension that this codebase relied on. + /// + public static void CopyNonDefault( + TSource source, + TDestination destination, + params string[] ignoredMembers) + where TSource : notnull + where TDestination : notnull + { + var sourceProps = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance); + var destType = typeof(TDestination); + + foreach (var srcProp in sourceProps) + { + if (!srcProp.CanRead) + { + continue; + } + + if (Array.IndexOf(ignoredMembers, srcProp.Name) >= 0) + { + continue; + } + + var destProp = destType.GetProperty(srcProp.Name, BindingFlags.Public | BindingFlags.Instance); + if (destProp == null || !destProp.CanWrite) + { + continue; + } + + if (!destProp.PropertyType.IsAssignableFrom(srcProp.PropertyType)) + { + continue; + } + + var value = srcProp.GetValue(source); + if (IsValueDefault(value)) + { + continue; + } + + destProp.SetValue(destination, value); + } + } + + private static bool IsValueDefault(object? value) + { + if (value == null) + { + return true; + } + + var type = value.GetType(); + if (!type.IsValueType) + { + return false; + } + + return value.Equals(Activator.CreateInstance(type)); + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs index b76bd5707e..376f652db0 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs @@ -1,3 +1,4 @@ +using Amazon.S3; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -11,7 +12,7 @@ using Unity.GrantManager.Intake; using Unity.GrantManager.Integrations.Css; using Unity.TenantManagement; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.BlobStoring; using Volo.Abp.FeatureManagement; using Volo.Abp.Identity; @@ -47,6 +48,7 @@ using Unity.GrantManager.GrantsPortal.Handlers; using Unity.GrantManager.Messaging; using Unity.GrantManager.Analytics; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Unity.GrantManager; @@ -126,9 +128,18 @@ public override void ConfigureServices(ServiceConfigurationContext context) }); }); - Configure(options => + context.Services.AddMapperlyObjectMapper(); + + context.Services.TryAddSingleton(_ => { - options.AddMaps(); + var s3Config = new AmazonS3Config + { + RegionEndpoint = null, + ServiceURL = configuration["S3:Endpoint"], + AllowAutoRedirect = true, + ForcePathStyle = true + }; + return new AmazonS3Client(configuration["S3:AccessKeyId"], configuration["S3:SecretAccessKey"], s3Config); }); context.Services.AddSingleton(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Identity/UnityPermissionAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Identity/UnityPermissionAppService.cs new file mode 100644 index 0000000000..4eff3d210f --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Identity/UnityPermissionAppService.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.PermissionManagement; +using Volo.Abp.SimpleStateChecking; + +namespace Unity.GrantManager.Identity; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(PermissionAppService), typeof(IPermissionAppService))] +public class UnityPermissionAppService( + IPermissionManager permissionManager, + IPermissionChecker permissionChecker, + IPermissionDefinitionManager permissionDefinitionManager, + IResourcePermissionManager resourcePermissionManager, + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IOptions options, + ISimpleStateCheckerManager simpleStateCheckerManager) + : PermissionAppService(permissionManager, permissionChecker, permissionDefinitionManager, resourcePermissionManager, resourcePermissionGrantRepository, options, simpleStateCheckerManager) +{ + protected override Task HasAdminRoleAsync() + { + return Task.FromResult( + CurrentUser.IsInRole("admin") || + CurrentUser.IsInRole(UnityRoles.SystemAdmin) || + CurrentUser.IsInRole(UnityRoles.ProgramManager) + ); + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Identity/UserImportAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Identity/UserImportAppService.cs index 8c9585998f..01547def96 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Identity/UserImportAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Identity/UserImportAppService.cs @@ -169,6 +169,13 @@ public async Task> SearchAsync(UserSearchDto importUserSearchDto) return users.GroupBy(u => u.UserGuid).Select(g => g.First()).ToList(); } + [Authorize(IdentityPermissions.Users.Update)] + public async Task SetUserRolesAsync(Guid userId, string[] roleNames) + { + var user = await _identityUserRepository.GetAsync(userId); + await _userManager.SetRolesAsync(user, roleNames); + } + private async Task CreateNewIdentityUserAsync(Guid newUserId, string? username, string? firstName, string? lastName, string? emailAddress) { if (string.IsNullOrWhiteSpace(emailAddress)) emailAddress = null; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/MapperlyDefaults.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj index d917f3c323..b5a7b1a9ca 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj @@ -3,7 +3,7 @@ - net9.0 + net10.0 enable Unity.GrantManager @@ -34,28 +34,32 @@ - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile index a8bc24a33f..c6104449bc 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile @@ -1,7 +1,7 @@ -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base WORKDIR /app -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY ["NuGet.Config", "."] COPY ["src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj", "src/Unity.GrantManager.DbMigrator/"] diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/GrantManagerDbMigratorModule.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/GrantManagerDbMigratorModule.cs index f3923a9200..135f89582e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/GrantManagerDbMigratorModule.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/GrantManagerDbMigratorModule.cs @@ -2,12 +2,14 @@ using Unity.GrantManager.EntityFrameworkCore; using Unity.Reporting; using Volo.Abp.Autofac; +using Volo.Abp.Http.Client; using Volo.Abp.Modularity; namespace Unity.GrantManager.DbMigrator; [DependsOn( typeof(AbpAutofacModule), + typeof(AbpHttpClientModule), typeof(GrantManagerEntityFrameworkCoreModule), typeof(GrantManagerApplicationContractsModule), typeof(ReportingApplicationModule), // Needed to seed Reporting data diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj index 7cfd0b2699..2890764e6f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj @@ -1,10 +1,10 @@ - + Exe - net9.0 + net10.0 enable @@ -18,24 +18,24 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + - - + + + - + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json index 452a5ac1d3..626191b07d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/appsettings.json @@ -1,7 +1,7 @@ { "ConnectionStrings": { - "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres", - "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres" + "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres;", + "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres;" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json index ce7fb443f2..486e25d523 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json @@ -493,6 +493,35 @@ "ApplicantContacts:SetPrimaryFailed": "Failed to set contact as primary.", "ApplicantContacts:ColumnName": "Name", "ApplicantContacts:ColumnPhone": "Phone (Work)", - "ApplicantContacts:ColumnSubmission": "Submission #" + "ApplicantContacts:ColumnSubmission": "Submission #", + + "ApplicationBatchApprovalRequest:Title": "Approve Applications", + "ApplicationBatchApprovalRequest:SubmitButtonText": "Approve", + "ApplicationBatchApprovalRequest:CancelButtonText": "Cancel", + "ApplicationBatchApprovalRequest:MaxCountExceeded": "You have exceeded the maximum number of items for bulk approval. Please reduce the number to {0} or fewer", + "ApplicationBatchApprovalRequest:DecisionDateDefaulted": "Decision Date has been defaulted", + "ApplicationBatchApprovalRequest:ApprovedAmountDefaulted": "Approved Amount has been defaulted", + "ApplicationBatchApprovalRequest:InvalidStatus": "The assessment for the selected item is not in the Assessment Completed state", + "ApplicationBatchApprovalRequest:InvalidPermissions": "Invalid permissions", + "ApplicationBatchApprovalRequest:InvalidApprovedAmount": "Invalid Approved Amount, it must be greater than 0.00", + "ApplicationBatchApprovalRequest:InvalidRecommendedAmount": "Invalid Recommended Amount, it must be greater than 0.00", + + "ApplicationLinks:Category": "Category", + "ApplicationLinks:ID": "ID", + "ApplicationLinks:Status": "Status", + "ApplicationLinks:LinkType": "Link Type", + + "ApplicantPortalSettings:Title": "Applicant Portal Configuration", + "ApplicantPortalSettings:ManageStatuses": "Manage Statuses", + "ApplicantPortalSettings:PortalStatusHeading": "Applicant Portal Status", + "ApplicantPortalSettings:InternalStatus": "Internal Status", + "ApplicantPortalSettings:PortalStatusLabel": "Portal Status Label", + "ApplicantPortalSettings:SaveChanges": "Save Changes", + "ApplicantPortalSettings:ResetChanges": "Reset", + "ApplicantPortalSettings:NoChanges": "No changes to save.", + "ApplicantPortalSettings:ChangesReset": "Changes have been reset to original values.", + "ApplicantPortalSettings:SaveSuccess": "Portal status labels updated successfully.", + "ApplicantPortalSettings:SaveError": "An error occurred while saving portal status labels.", + "ApplicantPortalSettings:ValidationRequired": "Portal status label cannot be empty." } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj index 38791bfc97..dea88fd8ef 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj @@ -1,27 +1,24 @@ - + - net9.0 + net10.0 enable Unity.GrantManager true - - - - - - - - - - - + + + + + + + + @@ -34,7 +31,7 @@ - + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj index b3f506871d..f1610fd590 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager @@ -15,20 +15,22 @@ - - + + - - - - - - - - - - + + + + + + + + + + + + **/Assessments/Assessment.cs, **/Assessments/AssessmentWithAssessorQueryResultItem.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs index 8e81c33850..31dd890f01 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantManagerDbContext.cs @@ -252,9 +252,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) var allEntityTypes = modelBuilder.Model.GetEntityTypes(); - foreach (var type in allEntityTypes.Where(t => t.ClrType != typeof(ExtraPropertyDictionary)).Select(t => t.ClrType)) + foreach (var entityType in allEntityTypes.Where(t => t.ClrType != typeof(ExtraPropertyDictionary) && !t.IsOwned())) { - var entityBuilder = modelBuilder.Entity(type); + var entityBuilder = modelBuilder.Entity(entityType.ClrType); entityBuilder.TryConfigureExtraProperties(); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs index fb1f585a96..0d70b15a5b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/EntityFrameworkCore/GrantTenantDbContext.cs @@ -400,9 +400,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) }); var allEntityTypes = modelBuilder.Model.GetEntityTypes(); - foreach (var type in allEntityTypes.Where(t => t.ClrType != typeof(ExtraPropertyDictionary)).Select(t => t.ClrType)) + foreach (var entityType in allEntityTypes.Where(t => t.ClrType != typeof(ExtraPropertyDictionary) && !t.IsOwned())) { - var entityBuilder = modelBuilder.Entity(type); + var entityBuilder = modelBuilder.Entity(entityType.ClrType); entityBuilder.TryConfigureExtraProperties(); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260428183200_Abp10_3_Upgrade.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260428183200_Abp10_3_Upgrade.Designer.cs new file mode 100644 index 0000000000..85dad8987b --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260428183200_Abp10_3_Upgrade.Designer.cs @@ -0,0 +1,3222 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Unity.GrantManager.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace Unity.GrantManager.Migrations.HostMigrations +{ + [DbContext(typeof(GrantManagerDbContext))] + [Migration("20260428183200_Abp10_3_Upgrade")] + partial class Abp10_3_Upgrade + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "10.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("BlobData") + .HasColumnType("bytea") + .HasColumnName("blob_data"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_blob_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCalendar", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("CalendarName") + .HasColumnType("text") + .HasColumnName("calendar_name"); + + b.Property("Calendar") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("calendar"); + + b.HasKey("SchedulerName", "CalendarName"); + + b.ToTable("qrtz_calendars", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCronTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("CronExpression") + .IsRequired() + .HasColumnType("text") + .HasColumnName("cron_expression"); + + b.Property("TimeZoneId") + .HasColumnType("text") + .HasColumnName("time_zone_id"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_cron_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzFiredTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("EntryId") + .HasColumnType("text") + .HasColumnName("entry_id"); + + b.Property("FiredTime") + .HasColumnType("bigint") + .HasColumnName("fired_time"); + + b.Property("InstanceName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("instance_name"); + + b.Property("IsNonConcurrent") + .HasColumnType("bool") + .HasColumnName("is_nonconcurrent"); + + b.Property("JobGroup") + .HasColumnType("text") + .HasColumnName("job_group"); + + b.Property("JobName") + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("RequestsRecovery") + .HasColumnType("bool") + .HasColumnName("requests_recovery"); + + b.Property("ScheduledTime") + .HasColumnType("bigint") + .HasColumnName("sched_time"); + + b.Property("State") + .IsRequired() + .HasColumnType("text") + .HasColumnName("state"); + + b.Property("TriggerGroup") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("TriggerName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.HasKey("SchedulerName", "EntryId"); + + b.HasIndex("InstanceName") + .HasDatabaseName("idx_qrtz_ft_trig_inst_name"); + + b.HasIndex("JobGroup") + .HasDatabaseName("idx_qrtz_ft_job_group"); + + b.HasIndex("JobName") + .HasDatabaseName("idx_qrtz_ft_job_name"); + + b.HasIndex("RequestsRecovery") + .HasDatabaseName("idx_qrtz_ft_job_req_recovery"); + + b.HasIndex("TriggerGroup") + .HasDatabaseName("idx_qrtz_ft_trig_group"); + + b.HasIndex("TriggerName") + .HasDatabaseName("idx_qrtz_ft_trig_name"); + + b.HasIndex("SchedulerName", "TriggerName", "TriggerGroup") + .HasDatabaseName("idx_qrtz_ft_trig_nm_gp"); + + b.ToTable("qrtz_fired_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("JobName") + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property("JobGroup") + .HasColumnType("text") + .HasColumnName("job_group"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("IsDurable") + .HasColumnType("bool") + .HasColumnName("is_durable"); + + b.Property("IsNonConcurrent") + .HasColumnType("bool") + .HasColumnName("is_nonconcurrent"); + + b.Property("IsUpdateData") + .HasColumnType("bool") + .HasColumnName("is_update_data"); + + b.Property("JobClassName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_class_name"); + + b.Property("JobData") + .HasColumnType("bytea") + .HasColumnName("job_data"); + + b.Property("RequestsRecovery") + .HasColumnType("bool") + .HasColumnName("requests_recovery"); + + b.HasKey("SchedulerName", "JobName", "JobGroup"); + + b.HasIndex("RequestsRecovery") + .HasDatabaseName("idx_qrtz_j_req_recovery"); + + b.ToTable("qrtz_job_details", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzLock", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("LockName") + .HasColumnType("text") + .HasColumnName("lock_name"); + + b.HasKey("SchedulerName", "LockName"); + + b.ToTable("qrtz_locks", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzPausedTriggerGroup", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.HasKey("SchedulerName", "TriggerGroup"); + + b.ToTable("qrtz_paused_trigger_grps", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSchedulerState", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("InstanceName") + .HasColumnType("text") + .HasColumnName("instance_name"); + + b.Property("CheckInInterval") + .HasColumnType("bigint") + .HasColumnName("checkin_interval"); + + b.Property("LastCheckInTime") + .HasColumnType("bigint") + .HasColumnName("last_checkin_time"); + + b.HasKey("SchedulerName", "InstanceName"); + + b.ToTable("qrtz_scheduler_state", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimplePropertyTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("BooleanProperty1") + .HasColumnType("bool") + .HasColumnName("bool_prop_1"); + + b.Property("BooleanProperty2") + .HasColumnType("bool") + .HasColumnName("bool_prop_2"); + + b.Property("DecimalProperty1") + .HasColumnType("numeric") + .HasColumnName("dec_prop_1"); + + b.Property("DecimalProperty2") + .HasColumnType("numeric") + .HasColumnName("dec_prop_2"); + + b.Property("IntegerProperty1") + .HasColumnType("integer") + .HasColumnName("int_prop_1"); + + b.Property("IntegerProperty2") + .HasColumnType("integer") + .HasColumnName("int_prop_2"); + + b.Property("LongProperty1") + .HasColumnType("bigint") + .HasColumnName("long_prop_1"); + + b.Property("LongProperty2") + .HasColumnType("bigint") + .HasColumnName("long_prop_2"); + + b.Property("StringProperty1") + .HasColumnType("text") + .HasColumnName("str_prop_1"); + + b.Property("StringProperty2") + .HasColumnType("text") + .HasColumnName("str_prop_2"); + + b.Property("StringProperty3") + .HasColumnType("text") + .HasColumnName("str_prop_3"); + + b.Property("TimeZoneId") + .HasColumnType("text") + .HasColumnName("time_zone_id"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_simprop_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimpleTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("RepeatCount") + .HasColumnType("bigint") + .HasColumnName("repeat_count"); + + b.Property("RepeatInterval") + .HasColumnType("bigint") + .HasColumnName("repeat_interval"); + + b.Property("TimesTriggered") + .HasColumnType("bigint") + .HasColumnName("times_triggered"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.ToTable("qrtz_simple_triggers", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b => + { + b.Property("SchedulerName") + .HasColumnType("text") + .HasColumnName("sched_name"); + + b.Property("TriggerName") + .HasColumnType("text") + .HasColumnName("trigger_name"); + + b.Property("TriggerGroup") + .HasColumnType("text") + .HasColumnName("trigger_group"); + + b.Property("CalendarName") + .HasColumnType("text") + .HasColumnName("calendar_name"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("EndTime") + .HasColumnType("bigint") + .HasColumnName("end_time"); + + b.Property("JobData") + .HasColumnType("bytea") + .HasColumnName("job_data"); + + b.Property("JobGroup") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_group"); + + b.Property("JobName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property("MisfireInstruction") + .HasColumnType("smallint") + .HasColumnName("misfire_instr"); + + b.Property("NextFireTime") + .HasColumnType("bigint") + .HasColumnName("next_fire_time"); + + b.Property("PreviousFireTime") + .HasColumnType("bigint") + .HasColumnName("prev_fire_time"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("StartTime") + .HasColumnType("bigint") + .HasColumnName("start_time"); + + b.Property("TriggerState") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_state"); + + b.Property("TriggerType") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trigger_type"); + + b.HasKey("SchedulerName", "TriggerName", "TriggerGroup"); + + b.HasIndex("NextFireTime") + .HasDatabaseName("idx_qrtz_t_next_fire_time"); + + b.HasIndex("TriggerState") + .HasDatabaseName("idx_qrtz_t_state"); + + b.HasIndex("NextFireTime", "TriggerState") + .HasDatabaseName("idx_qrtz_t_nft_st"); + + b.HasIndex("SchedulerName", "JobName", "JobGroup"); + + b.ToTable("qrtz_triggers", (string)null); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIPrompt", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("AIPrompts", "AI"); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIPromptVersion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeveloperNotes") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeprecated") + .HasColumnType("boolean"); + + b.Property("IsPublished") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MaxTokens") + .HasColumnType("integer"); + + b.Property("MetadataJson") + .HasColumnType("jsonb"); + + b.Property("PromptId") + .HasColumnType("uuid"); + + b.Property("SystemPrompt") + .IsRequired() + .HasColumnType("text"); + + b.Property("TargetModel") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TargetProvider") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Temperature") + .HasColumnType("double precision"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserPromptTemplate") + .IsRequired() + .HasColumnType("text"); + + b.Property("VersionNumber") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PromptId", "VersionNumber") + .IsUnique(); + + b.ToTable("AIPromptVersions", "AI"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applicants.ApplicantTenantMap", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastUpdated") + .HasColumnType("timestamp without time zone"); + + b.Property("OidcSubUsername") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TenantName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OidcSubUsername"); + + b.HasIndex("OidcSubUsername", "TenantId") + .IsUnique(); + + b.ToTable("ApplicantTenantMaps", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Integrations.CasClientCode", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientCode") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.Property("ClientId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinancialMinistry") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("MinistryPrefix") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.HasKey("Id"); + + b.ToTable("CasClientCodes", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Integrations.DynamicUrl", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("KeyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DynamicUrls", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.Community", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrictCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Communities", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.EconomicRegion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicRegionCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("EconomicRegionName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.ToTable("EconomicRegions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.ElectoralDistrict", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ElectoralDistrictCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("ElectoralDistrictName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.ToTable("ElectoralDistricts", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.RegionalDistrict", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicRegionCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("RegionalDistrictCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrictName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("RegionalDistricts", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.Sector", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SectorCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SectorName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Sectors", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.SubSector", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SectorId") + .HasColumnType("uuid"); + + b.Property("SubSectorCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubSectorName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("SectorId"); + + b.ToTable("SubSectors", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Messaging.InboxMessage", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DataType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Details") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MessageId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Payload") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ProcessedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ReceivedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RetryCount") + .HasColumnType("integer"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MessageId") + .IsUnique(); + + b.HasIndex("Source", "Status"); + + b.ToTable("InboxMessages", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Messaging.OutboxMessage", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AckStatus") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DataType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Details") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MessageId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("OriginalMessageId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("PublishedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RetryCount") + .HasColumnType("integer"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Source", "Status"); + + b.ToTable("OutboxMessages", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Tokens.TenantToken", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("TenantTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasColumnType("text"); + + b.Property("ExecutionDuration") + .HasColumnType("integer") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("integer") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uuid") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorTenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ImpersonatorTenantName"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uuid") + .HasColumnName("ImpersonatorUserId"); + + b.Property("ImpersonatorUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("ImpersonatorUserName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("TenantName"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AuditLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuditLogId") + .HasColumnType("uuid") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("integer") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AuditLogActions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogExcelFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("FileName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("FileName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AuditLogExcelFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuditLogId") + .HasColumnType("uuid") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("smallint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uuid"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("EntityChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EntityChangeId") + .HasColumnType("uuid"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("EntityPropertyChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsAbandoned") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("JobArgs") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("character varying(1048576)"); + + b.Property("JobName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("LastTryTime") + .HasColumnType("timestamp without time zone"); + + b.Property("NextTryTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)15); + + b.Property("TryCount") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)0); + + b.HasKey("Id"); + + b.HasIndex("IsAbandoned", "NextTryTime"); + + b.ToTable("BackgroundJobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("boolean"); + + b.Property("IsVisibleToClients") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Features", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("FeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("FeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("SourceTenantId") + .HasColumnType("uuid"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("TargetTenantId") + .HasColumnType("uuid"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique(); + + b.ToTable("LinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("boolean") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("boolean") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("SecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("LastAccessed") + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("SignedIn") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("Sessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("OidcSub") + .HasColumnType("text"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("boolean"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("EndTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("timestamp without time zone"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("UserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("character varying(196)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("UserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("bytea"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("UserPasswordHistories", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("UserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("character varying(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("OrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("OrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("ManagementPermissionName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("MultiTenancySide") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ResourceName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("ResourceName", "Name") + .IsUnique(); + + b.ToTable("Permissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("PermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("PermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.ResourcePermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ResourceKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ResourceName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ResourceName", "ResourceKey", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("ResourcePermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("Settings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("boolean"); + + b.Property("IsInherited") + .HasColumnType("boolean"); + + b.Property("IsVisibleToClients") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("SettingDefinitions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.HasIndex("NormalizedName"); + + b.ToTable("Tenants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("TenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("BlobTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCronTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("CronTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimplePropertyTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("SimplePropertyTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimpleTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", "Trigger") + .WithMany("SimpleTriggers") + .HasForeignKey("SchedulerName", "TriggerName", "TriggerGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b => + { + b.HasOne("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", "JobDetail") + .WithMany("Triggers") + .HasForeignKey("SchedulerName", "JobName", "JobGroup") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JobDetail"); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIPromptVersion", b => + { + b.HasOne("Unity.AI.Domain.AIPrompt", "Prompt") + .WithMany("Versions") + .HasForeignKey("PromptId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Prompt"); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.SubSector", b => + { + b.HasOne("Unity.GrantManager.Locality.Sector", "Sector") + .WithMany("SubSectors") + .HasForeignKey("SectorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Sector"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("UserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("jsonb"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.HasOne("Volo.Abp.TenantManagement.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", b => + { + b.Navigation("Triggers"); + }); + + modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b => + { + b.Navigation("BlobTriggers"); + + b.Navigation("CronTriggers"); + + b.Navigation("SimplePropertyTriggers"); + + b.Navigation("SimpleTriggers"); + }); + + modelBuilder.Entity("Unity.AI.Domain.AIPrompt", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("Unity.GrantManager.Locality.Sector", b => + { + b.Navigation("SubSectors"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260428183200_Abp10_3_Upgrade.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260428183200_Abp10_3_Upgrade.cs new file mode 100644 index 0000000000..fac0bfdb9c --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20260428183200_Abp10_3_Upgrade.cs @@ -0,0 +1,272 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.HostMigrations +{ + /// + public partial class Abp10_3_Upgrade : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Permissions_Name", + table: "Permissions"); + + migrationBuilder.AddColumn( + name: "LastSignInTime", + table: "Users", + type: "timestamp with time zone", + nullable: true); + + migrationBuilder.AddColumn( + name: "Leaved", + table: "Users", + type: "boolean", + nullable: false, + defaultValue: false); + + migrationBuilder.AlterColumn( + name: "DeviceInfo", + table: "Sessions", + type: "character varying(256)", + maxLength: 256, + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(64)", + oldMaxLength: 64, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "GroupName", + table: "Permissions", + type: "character varying(128)", + maxLength: 128, + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(128)", + oldMaxLength: 128); + + migrationBuilder.AddColumn( + name: "ManagementPermissionName", + table: "Permissions", + type: "character varying(128)", + maxLength: 128, + nullable: true); + + migrationBuilder.AddColumn( + name: "ResourceName", + table: "Permissions", + type: "character varying(256)", + maxLength: 256, + nullable: true); + + migrationBuilder.AlterColumn( + name: "PropertyTypeFullName", + table: "EntityPropertyChanges", + type: "character varying(512)", + maxLength: 512, + nullable: false, + oldClrType: typeof(string), + oldType: "character varying(64)", + oldMaxLength: 64); + + migrationBuilder.AlterColumn( + name: "EntityTypeFullName", + table: "EntityChanges", + type: "character varying(512)", + maxLength: 512, + nullable: false, + oldClrType: typeof(string), + oldType: "character varying(128)", + oldMaxLength: 128); + + migrationBuilder.AddColumn( + name: "ApplicationName", + table: "BackgroundJobs", + type: "character varying(96)", + maxLength: 96, + nullable: true); + + migrationBuilder.CreateTable( + name: "AuditLogExcelFiles", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + FileName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditLogExcelFiles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResourcePermissionGrants", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + Name = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + ProviderName = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + ProviderKey = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + ResourceName = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + ResourceKey = table.Column(type: "character varying(256)", maxLength: 256, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResourcePermissionGrants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "UserPasskeys", + columns: table => new + { + CredentialId = table.Column(type: "bytea", maxLength: 1024, nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + UserId = table.Column(type: "uuid", nullable: false), + Data = table.Column(type: "jsonb", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_UserPasskeys", x => x.CredentialId); + table.ForeignKey( + name: "FK_UserPasskeys_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserPasswordHistories", + columns: table => new + { + UserId = table.Column(type: "uuid", nullable: false), + Password = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserPasswordHistories", x => new { x.UserId, x.Password }); + table.ForeignKey( + name: "FK_UserPasswordHistories_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Permissions_ResourceName_Name", + table: "Permissions", + columns: new[] { "ResourceName", "Name" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ResourcePermissionGrants_TenantId_Name_ResourceName_Resourc~", + table: "ResourcePermissionGrants", + columns: new[] { "TenantId", "Name", "ResourceName", "ResourceKey", "ProviderName", "ProviderKey" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_UserPasskeys_UserId", + table: "UserPasskeys", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AuditLogExcelFiles"); + + migrationBuilder.DropTable( + name: "ResourcePermissionGrants"); + + migrationBuilder.DropTable( + name: "UserPasskeys"); + + migrationBuilder.DropTable( + name: "UserPasswordHistories"); + + migrationBuilder.DropIndex( + name: "IX_Permissions_ResourceName_Name", + table: "Permissions"); + + migrationBuilder.DropColumn( + name: "LastSignInTime", + table: "Users"); + + migrationBuilder.DropColumn( + name: "Leaved", + table: "Users"); + + migrationBuilder.DropColumn( + name: "ManagementPermissionName", + table: "Permissions"); + + migrationBuilder.DropColumn( + name: "ResourceName", + table: "Permissions"); + + migrationBuilder.DropColumn( + name: "ApplicationName", + table: "BackgroundJobs"); + + migrationBuilder.AlterColumn( + name: "DeviceInfo", + table: "Sessions", + type: "character varying(64)", + maxLength: 64, + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(256)", + oldMaxLength: 256, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "GroupName", + table: "Permissions", + type: "character varying(128)", + maxLength: 128, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "character varying(128)", + oldMaxLength: 128, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "PropertyTypeFullName", + table: "EntityPropertyChanges", + type: "character varying(64)", + maxLength: 64, + nullable: false, + oldClrType: typeof(string), + oldType: "character varying(512)", + oldMaxLength: 512); + + migrationBuilder.AlterColumn( + name: "EntityTypeFullName", + table: "EntityChanges", + type: "character varying(128)", + maxLength: 128, + nullable: false, + oldClrType: typeof(string), + oldType: "character varying(512)", + oldMaxLength: 512); + + migrationBuilder.CreateIndex( + name: "IX_Permissions_Name", + table: "Permissions", + column: "Name", + unique: true); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs index 70e4cdaeee..0685bc5805 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/GrantManagerDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) - .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("ProductVersion", "10.0.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -1562,6 +1562,34 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AuditLogActions", (string)null); }); + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogExcelFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("FileName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("FileName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AuditLogExcelFiles", (string)null); + }); + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => { b.Property("Id") @@ -1590,8 +1618,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EntityTypeFullName") .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") + .HasMaxLength(512) + .HasColumnType("character varying(512)") .HasColumnName("EntityTypeFullName"); b.Property("ExtraProperties") @@ -1638,8 +1666,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("PropertyTypeFullName") .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)") + .HasMaxLength(512) + .HasColumnType("character varying(512)") .HasColumnName("PropertyTypeFullName"); b.Property("TenantId") @@ -1659,6 +1687,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + b.Property("ConcurrencyStamp") .IsConcurrencyToken() .IsRequired() @@ -2087,8 +2119,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character varying(64)"); b.Property("DeviceInfo") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); + .HasMaxLength(256) + .HasColumnType("character varying(256)"); b.Property("ExtraProperties") .HasColumnType("text") @@ -2211,6 +2243,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("LastPasswordChangeTime") .HasColumnType("timestamp with time zone"); + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("boolean") @@ -2409,6 +2450,47 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("UserOrganizationUnits", (string)null); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("bytea"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("UserPasswordHistories", (string)null); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => { b.Property("UserId") @@ -2574,13 +2656,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnName("ExtraProperties"); b.Property("GroupName") - .IsRequired() .HasMaxLength(128) .HasColumnType("character varying(128)"); b.Property("IsEnabled") .HasColumnType("boolean"); + b.Property("ManagementPermissionName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + b.Property("MultiTenancySide") .HasColumnType("smallint"); @@ -2597,6 +2682,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(128) .HasColumnType("character varying(128)"); + b.Property("ResourceName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + b.Property("StateCheckers") .HasMaxLength(256) .HasColumnType("character varying(256)"); @@ -2605,7 +2694,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("GroupName"); - b.HasIndex("Name") + b.HasIndex("ResourceName", "Name") .IsUnique(); b.ToTable("Permissions", (string)null); @@ -2672,6 +2761,49 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("PermissionGroups", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.ResourcePermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ResourceKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ResourceName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ResourceName", "ResourceKey", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("ResourcePermissionGrants", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") @@ -2987,6 +3119,62 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("UserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("jsonb"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => { b.HasOne("Volo.Abp.Identity.IdentityRole", null) @@ -3093,6 +3281,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("OrganizationUnits"); + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + b.Navigation("Roles"); b.Navigation("Tokens"); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs index f05e882f74..1722b56484 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) - .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("ProductVersion", "10.0.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Unity.GrantManager.EntityFrameworkCore.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Unity.GrantManager.EntityFrameworkCore.csproj index 58bfb739d5..5cb2b1d7ba 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Unity.GrantManager.EntityFrameworkCore.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Unity.GrantManager.EntityFrameworkCore.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager @@ -59,22 +59,23 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi.Client/Unity.GrantManager.HttpApi.Client.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi.Client/Unity.GrantManager.HttpApi.Client.csproj index 1b64ed6548..f530096675 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi.Client/Unity.GrantManager.HttpApi.Client.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi.Client/Unity.GrantManager.HttpApi.Client.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager @@ -14,14 +14,11 @@ - - - - - - - - + + + + + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Unity.GrantManager.HttpApi.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Unity.GrantManager.HttpApi.csproj index 77574bfd51..d174f23920 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Unity.GrantManager.HttpApi.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Unity.GrantManager.HttpApi.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager @@ -15,15 +15,14 @@ - - - - - - - + + + + + + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Dockerfile b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Dockerfile index b83c1f36fe..7070c979a6 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Dockerfile +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base ENV ASPNETCORE_URLS="http://+:8080" EXPOSE 8080 443 WORKDIR /app -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src # set up node @@ -37,9 +37,9 @@ RUN dotnet restore "src/Unity.GrantManager.Web/Unity.GrantManager.Web.csproj" COPY . . WORKDIR "/src/src/Unity.GrantManager.Web" -RUN dotnet tool install -g Volo.Abp.Cli --version 9.1.3 +RUN dotnet tool install -g Volo.Abp.Cli --version 10.3.0 ENV PATH="${PATH}:/root/.dotnet/tools" -RUN dotnet dev-certs https --trust +#RUN dotnet dev-certs https --trust RUN abp install-libs FROM build AS publish @@ -54,7 +54,7 @@ RUN dotnet publish "Unity.GrantManager.Web.csproj" \ FROM base AS final WORKDIR /app -COPY --from=build /root/.dotnet/corefx/cryptography/x509stores/my/* /root/.dotnet/corefx/cryptography/x509stores/my/ +# COPY --from=build /root/.dotnet/corefx/cryptography/x509stores/my/* /root/.dotnet/corefx/cryptography/x509stores/my/ # CAS Dev/Test Certs changed - again Sept 17 COPY ["/src/Unity.GrantManager.Web/certs/cas2024inter.crt", "/usr/local/share/ca-certificates/cas2024inter.crt"] diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Filters/ApiTokenAuthorizationHeaderParameter.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Filters/ApiTokenAuthorizationHeaderParameter.cs index 50d7a76cfc..35f8b731b5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Filters/ApiTokenAuthorizationHeaderParameter.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Filters/ApiTokenAuthorizationHeaderParameter.cs @@ -1,7 +1,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; using System.Linq; namespace Unity.GrantManager.Web.Filters @@ -13,26 +14,16 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) if (context.ApiDescription.ActionDescriptor is ControllerActionDescriptor) { if (!context.ApiDescription.CustomAttributes().Any((a) => a is ServiceFilterAttribute)) - { + { return; } operation.Security ??= []; operation.Security.Add( - new OpenApiSecurityRequirement{ + new OpenApiSecurityRequirement { - new OpenApiSecurityScheme - { - In = ParameterLocation.Header, - Reference = new OpenApiReference - { - Type = ReferenceType.SecurityScheme, - Id = "ApiKey" - } - }, - System.Array.Empty() - } - }); + { new OpenApiSecuritySchemeReference("ApiKey"), new List() } + }); } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebAutoMapperProfile.cs deleted file mode 100644 index e38ed515e5..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebAutoMapperProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using Unity.GrantManager.ApplicantProfile; -using Unity.GrantManager.ApplicantProfile.ProfileData; -using Unity.GrantManager.Web.Pages.ApplicantContact; - -namespace Unity.GrantManager.Web; - -public class GrantManagerWebAutoMapperProfile : Profile -{ - public GrantManagerWebAutoMapperProfile() - { - CreateMap() - .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.ContactId)); - - CreateMap(); - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs index 957112a641..e6f9d5eb17 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/GrantManagerWebModule.cs @@ -12,7 +12,7 @@ using Microsoft.IdentityModel.Logging; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using StackExchange.Profiling; using StackExchange.Profiling.Storage; using System; @@ -54,7 +54,7 @@ using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Auditing; using Volo.Abp.Autofac; -using Volo.Abp.AutoMapper; +using Volo.Abp.Mapperly; using Volo.Abp.BlobStoring; using Volo.Abp.Identity; using Volo.Abp.Localization; @@ -419,10 +419,8 @@ private void ConfigureBundles() private void ConfigureAutoMapper() { - Configure(options => - { - options.AddMaps(); - }); + // Mapperly mappers in this assembly are auto-discovered by + // AbpMapperlyConventionalRegistrar. No explicit registration required. } private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/MapperlyDefaults.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/MapperlyDefaults.cs new file mode 100644 index 0000000000..11c6d37b53 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/MapperlyDefaults.cs @@ -0,0 +1,3 @@ +using Riok.Mapperly.Abstractions; + +[assembly: MapperDefaults(RequiredMappingStrategy = RequiredMappingStrategy.Target)] diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/ApplicationFormsMapper.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/ApplicationFormsMapper.cs deleted file mode 100644 index ecda7a520b..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/ApplicationFormsMapper.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using Unity.GrantManager.ApplicationForms; -using Unity.GrantManager.Forms; -using Unity.GrantManager.Web.Pages.ApplicationForms.ViewModels; - -namespace Unity.GrantManager.Web.Mapping -{ - public class ApplicationFormsMapper : Profile - { - public ApplicationFormsMapper() - { - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/GrantApplicationsMapper.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/GrantApplicationsMapper.cs deleted file mode 100644 index 914dde8e9a..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/GrantApplicationsMapper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using AutoMapper; -using Unity.GrantManager.Applications; -using Unity.GrantManager.GrantApplications; -using Unity.GrantManager.Web.Pages.ApplicationContact; -using Unity.GrantManager.Web.Pages.Sites.ViewModels; -using Unity.GrantManager.Web.Views.Shared.Components.ApplicantInfo; -using Unity.GrantManager.Web.Views.Shared.Components.SummaryWidget; -using Unity.Payments.Suppliers; - -namespace Unity.GrantManager.Web.Mapping; - -public class GrantApplicationsMapper : Profile -{ - public GrantApplicationsMapper() - { - CreateMap(); - CreateMap(). - ForMember(dest => dest.SubmissionDate, opt => opt.MapFrom(s => s.SubmissionDate == null ? "" : s.SubmissionDate.Value.ToShortDateString())); - CreateMap(); - CreateMap(); - - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap() - .ForMember(dest => dest.PostalCode, opt => opt.MapFrom(src => src.Postal)); - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/GrantManagerWebMapperlyProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/GrantManagerWebMapperlyProfile.cs new file mode 100644 index 0000000000..871ed14291 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/GrantManagerWebMapperlyProfile.cs @@ -0,0 +1,324 @@ +using System; +using Riok.Mapperly.Abstractions; +using Unity.GrantManager.ApplicantProfile; +using Unity.GrantManager.ApplicantProfile.ProfileData; +using Unity.GrantManager.ApplicationForms; +using Unity.GrantManager.Applications; +using Unity.GrantManager.Forms; +using Unity.GrantManager.GrantApplications; +using Unity.GrantManager.Identity; +using Unity.GrantManager.Intakes; +using Unity.GrantManager.SettingManagement; +using Unity.GrantManager.Web.Components.ApplicationUiSettingGroup; +using Unity.GrantManager.Web.Pages.ApplicantContact; +using Unity.GrantManager.Web.Pages.ApplicationContact; +using Unity.GrantManager.Web.Pages.ApplicationForms.ViewModels; +using Unity.GrantManager.Web.Pages.Sites.ViewModels; +using Unity.GrantManager.Web.Views.Shared.Components.ApplicantInfo; +using Unity.GrantManager.Web.Views.Shared.Components.SummaryWidget; +using Unity.Payments.Suppliers; +using Volo.Abp.Mapperly; + +namespace Unity.GrantManager.Web.Mapping; + +[Mapper] +public partial class ApplicationFormDtoToCreateUpdateApplicationFormDtoMapper : MapperBase +{ + public override partial CreateUpdateApplicationFormDto Map(ApplicationFormDto source); + public override partial void Map(ApplicationFormDto source, CreateUpdateApplicationFormDto destination); +} + +[Mapper] +public partial class CreateUpdateApplicationFormViewModelToDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.ChefsCriteriaFormGuid))] + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.Version))] + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.Payable))] + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.RenderFormIoToHtml))] + public override partial CreateUpdateApplicationFormDto Map(CreateUpdateApplicationFormViewModel source); + + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.ChefsCriteriaFormGuid))] + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.Version))] + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.Payable))] + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormDto.RenderFormIoToHtml))] + public override partial void Map(CreateUpdateApplicationFormViewModel source, CreateUpdateApplicationFormDto destination); +} + +[Mapper] +public partial class ApplicationFormDtoToViewModelMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormViewModel.IntakesList))] + public override partial CreateUpdateApplicationFormViewModel Map(ApplicationFormDto source); + + [MapperIgnoreTarget(nameof(CreateUpdateApplicationFormViewModel.IntakesList))] + public override partial void Map(ApplicationFormDto source, CreateUpdateApplicationFormViewModel destination); +} + +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ApplicationToGrantApplicationDtoWebMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(GrantApplicationDto.RowCount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Assignees))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Status))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Probability))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Category))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Sector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubSector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubStatusDisplayValue))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.StatusCode))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactFullName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactTitle))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactEmail))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactBusinessPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactCellPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationTag))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.NonRegOrgName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationType))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.BusinessNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationSize))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SectorSubSectorIndustryDesc))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.PaymentInfo))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.AIAnalysisData))] + public override partial GrantApplicationDto Map(Application source); + + + [MapperIgnoreTarget(nameof(GrantApplicationDto.RowCount))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Assignees))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Status))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Probability))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Category))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.Sector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubSector))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SubStatusDisplayValue))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.StatusCode))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactFullName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactTitle))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactEmail))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactBusinessPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ContactCellPhone))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.ApplicationTag))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.NonRegOrgName))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationType))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgStatus))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.BusinessNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrganizationSize))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.OrgNumber))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.SectorSubSectorIndustryDesc))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.PaymentInfo))] + [MapperIgnoreTarget(nameof(GrantApplicationDto.AIAnalysisData))] + public override partial void Map(Application source, GrantApplicationDto destination); + + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.SiteId))] + [MapperIgnoreTarget(nameof(GrantApplicationApplicantDto.ElectoralDistrict))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.FiscalDay), Use = nameof(ResolveApplicantFiscalDay))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.SupplierId), Use = nameof(ResolveApplicantSupplierId))] + [MapPropertyFromSource(nameof(GrantApplicationApplicantDto.RedStop), Use = nameof(ResolveApplicantRedStop))] + private partial GrantApplicationApplicantDto ToDto(Applicant source); + + [MapperIgnoreTarget(nameof(ApplicationFormDto.ChefsFormVersionGuid))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.SubmissionHeaderMapping))] + [MapperIgnoreTarget(nameof(ApplicationFormDto.ApiToken))] + private partial ApplicationFormDto ToDto(ApplicationForm source); + + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.AssigneeId))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.ApplicationId))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Duty))] + [MapperIgnoreTarget(nameof(GrantApplicationAssigneeDto.Email))] + private partial GrantApplicationAssigneeDto ToDto(Person source); + + private static string ResolveApplicantFiscalDay(Applicant src) => src.FiscalDay?.ToString() ?? string.Empty; + private static Guid ResolveApplicantSupplierId(Applicant src) => src.SupplierId ?? Guid.Empty; + private static bool ResolveApplicantRedStop(Applicant src) => src.RedStop ?? false; +} + +[Mapper(AllowNullPropertyAssignment = true)] +public partial class GetSummaryDtoToSummaryWidgetViewModelMapper : MapperBase +{ + [MapPropertyFromSource(nameof(SummaryWidgetViewModel.SubmissionDate), Use = nameof(ResolveSubmissionDate))] + [MapPropertyFromSource(nameof(SummaryWidgetViewModel.TotalScore), Use = nameof(ResolveTotalScore))] + [MapperIgnoreTarget(nameof(SummaryWidgetViewModel.ApplicationId))] + [MapperIgnoreTarget(nameof(SummaryWidgetViewModel.IsReadOnly))] + public override partial SummaryWidgetViewModel Map(GetSummaryDto source); + + [MapPropertyFromSource(nameof(SummaryWidgetViewModel.SubmissionDate), Use = nameof(ResolveSubmissionDate))] + [MapPropertyFromSource(nameof(SummaryWidgetViewModel.TotalScore), Use = nameof(ResolveTotalScore))] + [MapperIgnoreTarget(nameof(SummaryWidgetViewModel.ApplicationId))] + [MapperIgnoreTarget(nameof(SummaryWidgetViewModel.IsReadOnly))] + public override partial void Map(GetSummaryDto source, SummaryWidgetViewModel destination); + + private static string ResolveSubmissionDate(GetSummaryDto src) + => src.SubmissionDate == null ? string.Empty : src.SubmissionDate.Value.ToShortDateString(); + + private static int ResolveTotalScore(GetSummaryDto src) + => int.TryParse(src.TotalScore, out var result) ? result : 0; +} + +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ContactModalViewModelToDtoMapper : MapperBase +{ + public override partial ApplicationContactDto Map(ContactModalViewModel source); + public override partial void Map(ContactModalViewModel source, ApplicationContactDto destination); +} + +[Mapper] +public partial class ApplicationContactDtoToViewModelMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(ContactModalViewModel.ContactTypeList))] + public override partial ContactModalViewModel Map(ApplicationContactDto source); + + [MapperIgnoreTarget(nameof(ContactModalViewModel.ContactTypeList))] + public override partial void Map(ApplicationContactDto source, ContactModalViewModel destination); +} + +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ApplicantSummaryDtoToViewModelMapper : MapperBase +{ + public override partial ApplicantSummaryViewModel Map(ApplicantSummaryDto source); + public override partial void Map(ApplicantSummaryDto source, ApplicantSummaryViewModel destination); +} + +[Mapper] +public partial class ContactInfoDtoToViewModelMapper : MapperBase +{ + public override partial ContactInfoViewModel Map(ContactInfoDto source); + public override partial void Map(ContactInfoDto source, ContactInfoViewModel destination); +} + +[Mapper] +public partial class SigningAuthorityDtoToViewModelMapper : MapperBase +{ + public override partial SigningAuthorityViewModel Map(SigningAuthorityDto source); + public override partial void Map(SigningAuthorityDto source, SigningAuthorityViewModel destination); +} + +[Mapper] +public partial class SiteDtoToCreateUpdateSiteViewModelMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(CreateUpdateSiteViewModel.MailingAddress))] + public override partial CreateUpdateSiteViewModel Map(SiteDto source); + + [MapperIgnoreTarget(nameof(CreateUpdateSiteViewModel.MailingAddress))] + public override partial void Map(SiteDto source, CreateUpdateSiteViewModel destination); +} + +[Mapper] +public partial class CreateUpdateSiteViewModelToDtoMapper : MapperBase +{ + [MapperIgnoreTarget(nameof(SiteDto.AddressLine1))] + [MapperIgnoreTarget(nameof(SiteDto.AddressLine2))] + [MapperIgnoreTarget(nameof(SiteDto.AddressLine3))] + [MapperIgnoreTarget(nameof(SiteDto.City))] + [MapperIgnoreTarget(nameof(SiteDto.Province))] + [MapperIgnoreTarget(nameof(SiteDto.PostalCode))] + [MapperIgnoreTarget(nameof(SiteDto.SupplierId))] + [MapperIgnoreTarget(nameof(SiteDto.Country))] + [MapperIgnoreTarget(nameof(SiteDto.EmailAddress))] + [MapperIgnoreTarget(nameof(SiteDto.EFTAdvicePref))] + [MapperIgnoreTarget(nameof(SiteDto.ProviderId))] + [MapperIgnoreTarget(nameof(SiteDto.SiteProtected))] + [MapperIgnoreTarget(nameof(SiteDto.LastUpdatedInCas))] + [MapperIgnoreTarget(nameof(SiteDto.MarkDeletedInUse))] + [MapperIgnoreTarget(nameof(SiteDto.CreationTime))] + [MapperIgnoreTarget(nameof(SiteDto.CreatorId))] + [MapperIgnoreTarget(nameof(SiteDto.LastModificationTime))] + [MapperIgnoreTarget(nameof(SiteDto.LastModifierId))] + public override partial SiteDto Map(CreateUpdateSiteViewModel source); + + [MapperIgnoreTarget(nameof(SiteDto.AddressLine1))] + [MapperIgnoreTarget(nameof(SiteDto.AddressLine2))] + [MapperIgnoreTarget(nameof(SiteDto.AddressLine3))] + [MapperIgnoreTarget(nameof(SiteDto.City))] + [MapperIgnoreTarget(nameof(SiteDto.Province))] + [MapperIgnoreTarget(nameof(SiteDto.PostalCode))] + [MapperIgnoreTarget(nameof(SiteDto.SupplierId))] + [MapperIgnoreTarget(nameof(SiteDto.Country))] + [MapperIgnoreTarget(nameof(SiteDto.EmailAddress))] + [MapperIgnoreTarget(nameof(SiteDto.EFTAdvicePref))] + [MapperIgnoreTarget(nameof(SiteDto.ProviderId))] + [MapperIgnoreTarget(nameof(SiteDto.SiteProtected))] + [MapperIgnoreTarget(nameof(SiteDto.LastUpdatedInCas))] + [MapperIgnoreTarget(nameof(SiteDto.MarkDeletedInUse))] + [MapperIgnoreTarget(nameof(SiteDto.CreationTime))] + [MapperIgnoreTarget(nameof(SiteDto.CreatorId))] + [MapperIgnoreTarget(nameof(SiteDto.LastModificationTime))] + [MapperIgnoreTarget(nameof(SiteDto.LastModifierId))] + public override partial void Map(CreateUpdateSiteViewModel source, SiteDto destination); +} + +[Mapper] +public partial class ApplicantAddressDtoToViewModelMapper : MapperBase +{ + [MapProperty(nameof(ApplicantAddressDto.Postal), nameof(ApplicantAddressViewModel.PostalCode))] + [MapperIgnoreTarget(nameof(ApplicantAddressViewModel.ApplicantAddressId))] + public override partial ApplicantAddressViewModel Map(ApplicantAddressDto source); + + [MapProperty(nameof(ApplicantAddressDto.Postal), nameof(ApplicantAddressViewModel.PostalCode))] + [MapperIgnoreTarget(nameof(ApplicantAddressViewModel.ApplicantAddressId))] + public override partial void Map(ApplicantAddressDto source, ApplicantAddressViewModel destination); +} + +[Mapper] +public partial class IntakeDtoToCreateUpdateIntakeDtoMapper : MapperBase +{ + public override partial CreateUpdateIntakeDto Map(IntakeDto source); + public override partial void Map(IntakeDto source, CreateUpdateIntakeDto destination); +} + +[Mapper] +public partial class ApplicationUiSettingsDtoToViewModelMapper : MapperBase +{ + public override partial ApplicationUiSettingsViewModel Map(ApplicationUiSettingsDto source); + public override partial void Map(ApplicationUiSettingsDto source, ApplicationUiSettingsViewModel destination); +} + +[Mapper(AllowNullPropertyAssignment = true)] +public partial class ContactInfoItemDtoToApplicantContactModalViewModelMapper : MapperBase +{ + [MapProperty(nameof(ContactInfoItemDto.ContactId), nameof(ApplicantContactModalViewModel.Id))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.IsEditable))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.ApplicationId))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.ReferenceNo))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.CreationTime))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.HomePhoneNumber))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.WorkPhoneExtension))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.ContactType))] + [MapperIgnoreTarget(nameof(ApplicantContactModalViewModel.ApplicantId))] + [MapperIgnoreTarget(nameof(ApplicantContactModalViewModel.RoleOptions))] + public override partial ApplicantContactModalViewModel Map(ContactInfoItemDto source); + + [MapProperty(nameof(ContactInfoItemDto.ContactId), nameof(ApplicantContactModalViewModel.Id))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.IsEditable))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.ApplicationId))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.ReferenceNo))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.CreationTime))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.HomePhoneNumber))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.WorkPhoneExtension))] + [MapperIgnoreSource(nameof(ContactInfoItemDto.ContactType))] + [MapperIgnoreTarget(nameof(ApplicantContactModalViewModel.ApplicantId))] + [MapperIgnoreTarget(nameof(ApplicantContactModalViewModel.RoleOptions))] + public override partial void Map(ContactInfoItemDto source, ApplicantContactModalViewModel destination); +} + +[Mapper] +public partial class ApplicantContactModalViewModelToUpdateApplicantContactDtoMapper : MapperBase +{ + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.ApplicantId))] + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.Id))] + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.IsPrimaryInferred))] + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.RoleOptions))] + [MapperIgnoreTarget(nameof(UpdateApplicantContactDto.WorkPhoneExtension))] + public override partial UpdateApplicantContactDto Map(ApplicantContactModalViewModel source); + + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.ApplicantId))] + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.Id))] + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.IsPrimaryInferred))] + [MapperIgnoreSource(nameof(ApplicantContactModalViewModel.RoleOptions))] + [MapperIgnoreTarget(nameof(UpdateApplicantContactDto.WorkPhoneExtension))] + public override partial void Map(ApplicantContactModalViewModel source, UpdateApplicantContactDto destination); +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/IntakesMapper.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/IntakesMapper.cs deleted file mode 100644 index d818542674..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/IntakesMapper.cs +++ /dev/null @@ -1,13 +0,0 @@ -using AutoMapper; -using Unity.GrantManager.Intakes; - -namespace Unity.GrantManager.Web.Mapping -{ - public class IntakesMapper : Profile - { - public IntakesMapper() - { - CreateMap(); - } - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/SettingsMapper.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/SettingsMapper.cs deleted file mode 100644 index 0da2b113aa..0000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Mapping/SettingsMapper.cs +++ /dev/null @@ -1,13 +0,0 @@ -using AutoMapper; -using Unity.GrantManager.SettingManagement; -using Unity.GrantManager.Web.Components.ApplicationUiSettingGroup; - -namespace Unity.GrantManager.Web.Mapping; - -public class SettingsMapper : Profile -{ - public SettingsMapper() - { - CreateMap(); - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.js index 1cc5e6af97..a698cbf33e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.js @@ -8,7 +8,7 @@ let worksheetMapColumn = document.querySelector('#worksheet-map-available-fields-column'); let excludedIntakeMappings = ['ConfirmationId', 'SubmissionId', 'SubmissionDate']; let dataTable; - toastr.options.positionClass = 'toast-top-center'; + if (globalThis.toastr) { toastr.options.positionClass = 'toast-top-center'; } let allowableTypes = ['textarea', 'orgbook', @@ -77,7 +77,7 @@ function init() { bindUIEvents(); dataTable = initializeDataTable(); - let availableChefsFields = JSON.parse(availableChefFieldsString) + let availableChefsFields = availableChefFieldsString ? JSON.parse(availableChefFieldsString) : [] initializeIntakeMap(availableChefsFields); bindExistingMaps(); setupTooltips(); @@ -146,7 +146,7 @@ ); setTimeout(function () { - window.location.href = location.href; + globalThis.location.href = location.href; }, 500); } @@ -181,7 +181,7 @@ ); setTimeout(function () { - const url = new URL(window.location.href); + const url = new URL(globalThis.location.href); // If this really is a GUID, validate it defensively if (!/^[0-9a-fA-F-]{36}$/.test(chefsFormVersionGuid)) { @@ -190,7 +190,7 @@ } url.searchParams.set("ChefsFormVersionGuid", chefsFormVersionGuid); - window.location.href = url.toString(); + globalThis.location.href = url.toString(); }, 500); } @@ -346,7 +346,7 @@ function handleReset() { $(intakeMapColumn).empty(); $(worksheetMapColumn).empty(); - let availableChefsFields = JSON.parse(availableChefFieldsString) + let availableChefsFields = availableChefFieldsString ? JSON.parse(availableChefFieldsString) : [] initializeIntakeMap(availableChefsFields); bindExistingMaps(); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/Index.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/Index.cshtml index 59dfcfa43e..a53c96f106 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/Index.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/Index.cshtml @@ -218,9 +218,28 @@
+
+
+ + + +
@await Component.InvokeAsync("Scoresheet")
+
+ +
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/PaymentConfigurations.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/PaymentConfigurations.js index 8cd446f471..37eb10a1eb 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/PaymentConfigurations.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/PaymentConfigurations.js @@ -8,7 +8,6 @@ $(function () { const formatter = createNumberFormatter(); const l = abp.localization.getResource('GrantManager'); - toastr.options.positionClass = 'toast-top-center'; const UIElements = { accountCodingDT: $('#AccountCodesDataTable'), @@ -283,12 +282,12 @@ $(function () { function updatePaymentPrefix() { unity.payments.paymentConfigurations.paymentConfiguration.updatePaymentPrefix(UIElements.paymentPrefixInput.val()) .done(function () { - toastr.success('Payment prefix updated successfully.'); + abp.notify.success('Payment prefix updated successfully.'); $('#payment-id-prefix-original').val(UIElements.paymentPrefixInput.val()); checkEnableDiscard(); }) .fail(function () { - toastr.error('Failed to update payment prefix.'); + abp.notify.error('Failed to update payment prefix.'); }); } @@ -300,7 +299,7 @@ $(function () { function discardPaymentPrefix() { UIElements.paymentPrefixInput.val(UIElements.originalPaymentPrefix.val()); - toastr.info('Payment prefix changes discarded.'); + abp.notify.info('Payment prefix changes discarded.'); checkEnableDiscard(); } @@ -394,10 +393,10 @@ function clearFilter() { function handleDefaultAccountCodeRadioClick(id) { $('#AccountCodingId').val(id); unity.payments.paymentConfigurations.paymentConfiguration.setDefaultAccountCode(id).done(function () { - toastr.success('Successfully set default account code. Reloading account codes.'); + abp.notify.success('Successfully set default account code. Reloading account codes.'); clearAccountCodesSearchAndReload(); }).fail(function () { - toastr.error('Failed to set default account code.'); + abp.notify.error('Failed to set default account code.'); }); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/ScoresheetConfiguration.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/ScoresheetConfiguration.js index b60cbf7393..059e0513d7 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/ScoresheetConfiguration.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ConfigurationManagement/ScoresheetConfiguration.js @@ -1,6 +1,43 @@ /* ScoresheetConfiguration JS - local copy for ConfigurationManagement */ +globalThis.importScoresheetFile = function (inputId) { + let input = document.getElementById(inputId); + let file = input.files[0]; + if (!file) return; + + const maxFileSize = decodeURIComponent($("#MaxFileSize").val()); + if ((file.size * 0.000001) > maxFileSize) { + input.value = null; + return abp.notify.error('File size exceeds ' + maxFileSize + 'MB', 'Error'); + } + + let formData = new FormData(); + formData.append("file", file); + + $.ajax({ + url: "/api/app/scoresheet/import", + data: formData, + processData: false, + contentType: false, + type: "POST", + success: function (data) { + abp.notify.success(data.responseText, 'Scoresheet Import Is Successful'); + PubSub.publish('refresh_scoresheet_list', { scoresheetId: null }); + input.value = null; + }, + error: function () { + abp.notify.error('Import failed.', 'Scoresheet Import Error'); + input.value = null; + } + }); +}; + (function ($) { + $(function () { + $('#scoresheet_import_upload_btn').on('click', function () { + $('#scoresheet_import_upload').trigger('click'); + }); + }); const scoresheetModal = new abp.ModalManager({ viewUrl: 'ScoresheetConfiguration/ScoresheetModal' }); @@ -45,7 +82,7 @@ }); // Exposed globally — called from inline onclick attributes in Scoresheet component HTML - window.openScoresheetModal = function (scoresheetId, actionType) { + globalThis.openScoresheetModal = function (scoresheetId, actionType) { scoresheetToEditId = scoresheetId; scoresheetModal.open({ scoresheetId: scoresheetId, @@ -53,14 +90,14 @@ }); }; - window.openCloneScoresheetModal = function (scoresheetId) { + globalThis.openCloneScoresheetModal = function (scoresheetId) { scoresheetToEditId = scoresheetId; cloneScoresheetModal.open({ scoresheetId: scoresheetId }); }; - window.openPublishScoresheetModal = function (scoresheetId) { + globalThis.openPublishScoresheetModal = function (scoresheetId) { scoresheetToEditId = scoresheetId; publishScoresheetModal.open({ scoresheetId: scoresheetId diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Dashboard/Index.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Dashboard/Index.cshtml.cs index d3a725acaa..816118f851 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Dashboard/Index.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/Dashboard/Index.cshtml.cs @@ -96,13 +96,13 @@ join formsq in await _applicationFormRepository.GetQueryableAsync() on intakesq. if (intakeR.Count == 0) return; IntakeOptionsList = intakeR.DistinctBy(s => s.IntakeId).Select(intake => new SelectListItem { Value = intake.IntakeId.ToString(), Text = intake.IntakeName }).ToList(); - var latestIntakeId = intakeR.OrderByDescending(intake => intake.IntakeCreationTime).FirstOrDefault()?.IntakeId; + var latestIntakeId = intakeR.OrderByDescending(intake => intake.IntakeCreationTime).First()?.IntakeId; IntakeIds = [latestIntakeId ?? Guid.Empty]; foreach (var intake in intakeR) { List categoryList = [.. intakeR.Where(s => !string.IsNullOrWhiteSpace(s.Category) && s.IntakeId == intake.IntakeId) - .Select(s => s.Category) + .Select(s => s.Category!) .Distinct() .OrderBy(c => c)]; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml index 6c970406ee..1b2cd15d4d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml @@ -286,13 +286,7 @@ } - @if (Model.CanViewPromptTools) - { - - } - +
@@ -512,93 +506,7 @@
} @*-------- AI Analysis Tab Section END ---------*@ - @if (Model.CanViewPromptTools) - { -
-
-
Prompt Tools
-
-
- -
-
-
-
- -
-
-
Attachment Summary
- -
-
-
- -
- -
-
- -
-
-
Application Analysis
- -
-
-
- -
- -
-
- -
-
-
Application Scoring
- -
-
-
- -
- -
-
-
-
- } -
+
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs index 829d28a058..151093e328 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs @@ -16,7 +16,6 @@ using Unity.GrantManager.Applications; using Unity.GrantManager.Flex; using Unity.GrantManager.GrantApplications; -using Unity.AI.Web.PromptTools; using Unity.GrantManager.Zones; using Unity.Modules.Shared.Correlation; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; @@ -33,7 +32,6 @@ public class DetailsModel : AbpPageModel private readonly IApplicationFormVersionAppService _applicationFormVersionAppService; private readonly IScoresheetRepository _scoresheetRepository; private readonly IFeatureChecker _featureChecker; - private readonly IAIPromptToolAccessProvider _aiPromptToolAccessProvider; protected readonly IZoneManagementAppService _zoneManagementAppService; [BindProperty(SupportsGet = true)] @@ -95,12 +93,6 @@ public class DetailsModel : AbpPageModel [BindProperty] public HashSet ZoneStateSet { get; set; } = []; - [BindProperty(SupportsGet = true)] - public bool CanViewPromptTools { get; set; } - - [BindProperty(SupportsGet = true)] - public string DefaultPromptVersion { get; set; } - [BindProperty(SupportsGet = true)] public string? ApplicationScoresheetSchemaJson { get; set; } @@ -112,7 +104,6 @@ public DetailsModel( IFeatureChecker featureChecker, ICurrentUser currentUser, IConfiguration configuration, - IAIPromptToolAccessProvider aiPromptToolAccessProvider, IZoneManagementAppService zoneManagementAppService) { _grantApplicationAppService = grantApplicationAppService; @@ -121,7 +112,6 @@ public DetailsModel( _applicationFormVersionAppService = applicationFormVersionAppService; _scoresheetRepository = scoresheetRepository; _zoneManagementAppService = zoneManagementAppService; - _aiPromptToolAccessProvider = aiPromptToolAccessProvider; CurrentUserId = currentUser.Id; CurrentUserName = currentUser.SurName + ", " + currentUser.Name; @@ -129,12 +119,10 @@ public DetailsModel( MaxFileSize = configuration["S3:MaxFileSize"] ?? ""; EmailAttachmentMaxFileSize = configuration["S3:EmailAttachmentMaxFileSize"] ?? "20"; TotalEmailAttachmentMaxFileSize = configuration["S3:EmailAttachmentsTotalMaxFileSize"] ?? "25"; - DefaultPromptVersion = aiPromptToolAccessProvider.DefaultPromptVersion; } public async Task OnGetAsync() { - CanViewPromptTools = await _aiPromptToolAccessProvider.CanViewPromptToolsAsync(); ApplicationFormSubmission applicationFormSubmission = await _grantApplicationAppService.GetFormSubmissionByApplicationId(ApplicationId); ZoneStateSet = await _zoneManagementAppService.GetZoneStateSetAsync(applicationFormSubmission.ApplicationFormId); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.css b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.css index 7cd0f382d1..2262bfdf1c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.css +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.css @@ -724,84 +724,3 @@ form label.error { background-color: #f9fafb; border-color: #9ca3af; } -.prompt-tools-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.75rem 1rem; - flex-wrap: nowrap; -} - -.prompt-tools-header .prompt-tools-toolbar-row { - display: flex; - align-items: center; - gap: 0.5rem 0.75rem; - margin-left: auto; -} - -.prompt-tools-header select, -.prompt-tools-header .form-select { - width: auto; - white-space: nowrap; -} - -.prompt-tools-section { - margin-bottom: 1rem; - padding-bottom: 1rem; - border-bottom: 1px solid #e7ebef; -} - -.prompt-tools-section:last-child { - margin-bottom: 0; - padding-bottom: 0; - border-bottom: 0; -} - -.prompt-tools-section-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.75rem 1rem; - margin-bottom: 0.5rem; -} - -.prompt-tools-section-header h6 { - min-width: 0; - flex: 1 1 auto; -} - -.prompt-tools-output-container { - position: relative; -} - -.prompt-tools-output-container .prompt-tools-output-actions { - position: absolute; - top: 0.375rem; - right: 0.5rem; - display: inline-flex; - align-items: center; - gap: 0.25rem; - z-index: 1; - padding: 0 0.25rem; - background: #ffffff; - border-radius: 999px; -} - -.prompt-tools-output-container .prompt-tools-output { - min-height: 10rem; - max-height: 24rem; - overflow: auto; - resize: vertical; - white-space: pre; - font-family: Consolas, "Courier New", monospace; - line-height: 1.35; - padding-top: 0.75rem; - padding-right: 2.5rem; -} - -.prompt-tools-output-container .prompt-tools-output-copy-btn { - width: 2rem; - height: 2rem; - padding: 0; - color: #5c6b7a; -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.js index dbdca9ddda..72b1bd1b33 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.js @@ -2,507 +2,7 @@ * Grant Application Details Page * Dependencies: ai-analysis.js - handles AI analysis rendering and management */ -function formatJsonOrRaw(value) { - if (!value) { - return ''; - } - - if (typeof value !== 'string') { - return JSON.stringify(value, null, 2); - } - - try { - return JSON.stringify(JSON.parse(value), null, 2); - } catch { - return value; - } -} - -function formatSectionBody(title, value) { - if (!value) { - return ''; - } - - return `${title}:\n${value}`; -} - -function formatOutputBody(title, sections) { - const content = sections.filter(Boolean).join('\n\n'); - if (!content) { - return ''; - } - - return `${title}\n\n${content}`; -} - -function getAIGenerationFailureMessage(operationType) { - switch (operationType) { - case 'attachment-summary': - return 'AI attachment summary failed.'; - case 'application-scoring': - return 'AI application scoring failed.'; - default: - return 'AI operation failed.'; - } -} - -function unwrapWhenResult(result) { - if ( - Array.isArray(result) && - result.length === 3 && - typeof result[1] === 'string' - ) { - return result[0]; - } - - return result; -} - -function extractSubmissionDataObject(root) { - if (!root || typeof root !== 'object' || Array.isArray(root)) { - return null; - } - - if (root.data && typeof root.data === 'object' && !Array.isArray(root.data)) { - return root.data; - } - - if ( - root.submission && - typeof root.submission === 'object' && - !Array.isArray(root.submission) && - root.submission.data && - typeof root.submission.data === 'object' && - !Array.isArray(root.submission.data) - ) { - return root.submission.data; - } - - return root; -} - -function formatTimestamp(value) { - if (!value) { - return ''; - } - - const timestamp = new Date(value); - if (Number.isNaN(timestamp.getTime())) { - return ''; - } - - return timestamp.toLocaleString(); -} - -function getAttachmentSummaryValue(attachment) { - return attachment?.aiSummary ?? attachment?.aISummary ?? ''; -} - -function formatAttachmentSummaryBody(attachments) { - if (!Array.isArray(attachments) || attachments.length === 0) { - return ''; - } - - const summarizedAttachments = attachments.filter( - (attachment) => { - const summary = getAttachmentSummaryValue(attachment); - return summary && summary.trim() !== ''; - } - ); - - if (summarizedAttachments.length === 0) { - return ''; - } - - return summarizedAttachments.map(function(attachment) { - const summary = getAttachmentSummaryValue(attachment); - return [ - 'NAME:', - attachment.fileName || '', - '', - 'SUMMARY:', - summary - ].join('\n'); - }).join('\n\n----------------------------------------\n\n'); -} - -function formatAttachmentSummaryJson(attachments) { - if (!Array.isArray(attachments) || attachments.length === 0) { - return ''; - } - - const summarizedAttachments = attachments - .map((attachment) => { - const summary = getAttachmentSummaryValue(attachment); - if (!summary || summary.trim() === '') { - return null; - } - - return { - name: attachment.fileName || '', - summary - }; - }) - .filter((attachment) => attachment !== null); - - if (summarizedAttachments.length === 0) { - return ''; - } - - return JSON.stringify(summarizedAttachments, null, 2); -} - $(function () { - const excludedPromptDataKeys = new Set([ - 'simplefile', - 'applicantAgent', - 'submit', - 'lateEntry', - 'metadata', - 'full_application_form_submission', - 'files', - 'file', - 'attachments' - ]); - - const nonDataComponentTypes = new Set([ - 'button', - 'simplebuttonadvanced', - 'html', - 'htmlelement', - 'content', - 'simpleseparator' - ]); - - globalThis.getSelectedPromptVersion = function() { - return $('#promptVersion').val() || null; - }; - - function setPromptToolsOutput(selector, value) { - $(selector).val(value || ''); - } - - function setPromptToolsTimestamp(selector, value) { - $(selector).text(value ? `(${value})` : ''); - } - - function getScoresheetSchemaJson() { - return $('#ApplicationScoresheetSchemaJson').val() || - $('#AssessmentScoresheetSchemaJson').val() || - ''; - } - - function hasPromptTools() { - return $('#prompt-tools').length > 0 && $('#promptVersion').length > 0; - } - - function getPromptDataPayload() { - const submissionJson = $('#ApplicationFormSubmissionData').val(); - if (!submissionJson) { - return ''; - } - - try { - const root = JSON.parse(submissionJson); - const submissionData = extractSubmissionDataObject(root); - if (!submissionData || typeof submissionData !== 'object' || Array.isArray(submissionData)) { - return ''; - } - - const filteredValues = { ...submissionData }; - for (const key of excludedPromptDataKeys) { - delete filteredValues[key]; - } - - const allowedSchemaKeys = extractAllowedSchemaKeys($('#ApplicationFormSchema').val()); - const payload = allowedSchemaKeys.size > 0 - ? Object.fromEntries( - Object.entries(filteredValues).filter(([key]) => allowedSchemaKeys.has(key)) - ) - : filteredValues; - - return JSON.stringify(payload, null, 2); - } catch { - return ''; - } - } - - function extractAllowedSchemaKeys(formSchema) { - if (!formSchema) { - return new Set(); - } - - try { - const schema = JSON.parse(formSchema); - const keys = new Set(); - extractSchemaKeys(schema.components, keys); - return keys; - } catch { - return new Set(); - } - } - - function extractSchemaKeys(components, keys) { - if (!Array.isArray(components)) { - return; - } - - for (const component of components) { - if (!component || typeof component !== 'object') { - continue; - } - - const key = component.key; - const type = component.type; - const isInput = component.input === true; - - if ( - typeof key === 'string' && - typeof type === 'string' && - !nonDataComponentTypes.has(type.toLowerCase()) && - isInput - ) { - keys.add(key); - } - - if (Array.isArray(component.components)) { - extractSchemaKeys(component.components, keys); - } - - if (Array.isArray(component.columns)) { - for (const column of component.columns) { - if (column && Array.isArray(column.components)) { - extractSchemaKeys(column.components, keys); - } - } - } - } - } - - function formatAttachmentAiOutput(attachments) { - const attachmentBody = formatAttachmentSummaryBody(attachments); - if (!attachmentBody) { - setPromptToolsTimestamp('#attachmentOutputTimestamp', ''); - return ''; - } - - const summarizedAttachments = attachments.filter( - (attachment) => { - const summary = getAttachmentSummaryValue(attachment); - return summary && summary.trim() !== ''; - } - ); - - const latestTimestamp = summarizedAttachments - .map((attachment) => attachment.lastModificationTime || attachment.creationTime || null) - .filter((timestamp) => !!timestamp) - .sort() - .at(-1); - - setPromptToolsTimestamp('#attachmentOutputTimestamp', formatTimestamp(latestTimestamp)); - return attachmentBody; - } - - function loadPromptToolsOutputs() { - if (!hasPromptTools()) { - return; - } - - const applicationId = $('#DetailsViewApplicationId').val(); - - if (!applicationId) { - setPromptToolsOutput('#analysisOutput', ''); - setPromptToolsOutput('#scoringOutput', ''); - setPromptToolsOutput('#attachmentOutput', ''); - setPromptToolsTimestamp('#analysisOutputTimestamp', ''); - setPromptToolsTimestamp('#scoringOutputTimestamp', ''); - setPromptToolsTimestamp('#attachmentOutputTimestamp', ''); - return; - } - - $.when( - unity.grantManager.grantApplications.grantApplication.get(applicationId), - unity.grantManager.attachments.attachment.getApplicationChefsFileAttachments(applicationId) - ) - .done(function(applicationResponse, attachmentsResponse) { - const application = unwrapWhenResult(applicationResponse); - const attachments = unwrapWhenResult(attachmentsResponse); - const updatedAt = application?.lastModificationTime || application?.creationTime || null; - const formattedUpdatedAt = formatTimestamp(updatedAt); - const attachmentSection = formatSectionBody('ATTACHMENTS', formatAttachmentSummaryJson(attachments)); - setPromptToolsTimestamp('#analysisOutputTimestamp', formattedUpdatedAt); - setPromptToolsTimestamp('#scoringOutputTimestamp', formattedUpdatedAt); - setPromptToolsOutput( - '#analysisOutput', - formatOutputBody('APPLICATION ANALYSIS', [ - formatSectionBody('DATA', getPromptDataPayload()), - attachmentSection, - formatSectionBody( - 'OUTPUT', - formatJsonOrRaw(application?.aiAnalysisData ?? application?.aiAnalysis ?? '') - ) - ]) - ); - setPromptToolsOutput( - '#scoringOutput', - formatOutputBody('APPLICATION SCORING', [ - formatSectionBody('SCORESHEET', formatJsonOrRaw(getScoresheetSchemaJson())), - formatSectionBody('DATA', getPromptDataPayload()), - attachmentSection, - formatSectionBody( - 'OUTPUT', - formatJsonOrRaw(application?.aiScoresheetAnswers ?? application?.aIScoresheetAnswers ?? '') - ) - ]) - ); - setPromptToolsOutput( - '#attachmentOutput', - formatOutputBody('ATTACHMENT SUMMARY', [formatAttachmentAiOutput(attachments)]) - ); - }) - .fail(function() { - setPromptToolsOutput('#analysisOutput', ''); - setPromptToolsOutput('#scoringOutput', ''); - setPromptToolsOutput('#attachmentOutput', ''); - setPromptToolsTimestamp('#analysisOutputTimestamp', ''); - setPromptToolsTimestamp('#scoringOutputTimestamp', ''); - setPromptToolsTimestamp('#attachmentOutputTimestamp', ''); - }); - } - - let aiGenerationPollTimeoutId = null; - const aiGenerationPollIntervalMs = 15000; - - function stopAIGenerationPolling() { - if (aiGenerationPollTimeoutId) { - clearTimeout(aiGenerationPollTimeoutId); - aiGenerationPollTimeoutId = null; - } - } - - function pollAIGenerationStatus(applicationId, operationType, promptVersion, restoreButton, originalHtml) { - const poll = function() { - unity.grantManager.grantApplications.grantApplication - .getAIGenerationStatus(applicationId, operationType, promptVersion) - .done(function(request) { - const statusText = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; - - if (statusText === 'Failed') { - stopAIGenerationPolling(); - globalThis.AIGenerationButtonState?.restore(restoreButton); - restoreButton.html(originalHtml).prop('disabled', false); - loadPromptToolsOutputs(); - abp.message.error(request?.failureReason || getAIGenerationFailureMessage(operationType)); - return; - } - - if (!request || request.isActive === false || statusText === 'Completed') { - stopAIGenerationPolling(); - setPromptToolsTimestamp('#analysisOutputTimestamp', request?.completedAt || request?.startedAt || null); - setPromptToolsTimestamp('#scoringOutputTimestamp', request?.completedAt || request?.startedAt || null); - loadPromptToolsOutputs(); - globalThis.AIGenerationButtonState?.setCompleted(restoreButton); - restoreButton.html('Completed').prop('disabled', true); - return; - } - - aiGenerationPollTimeoutId = setTimeout(poll, aiGenerationPollIntervalMs); - }) - .fail(function() { - aiGenerationPollTimeoutId = setTimeout(poll, aiGenerationPollIntervalMs); - }); - }; - - stopAIGenerationPolling(); - aiGenerationPollTimeoutId = setTimeout(poll, 500); - } - - function queueAIGenerationOperation(queueAction, operationType, failureMessage, restoreButton, originalHtml) { - queueAction() - .done(function(request) { - pollAIGenerationStatus( - $('#DetailsViewApplicationId').val(), - operationType, - globalThis.getSelectedPromptVersion?.() || null, - restoreButton, - originalHtml - ); - }) - .fail(function() { - abp.message.error(failureMessage); - globalThis.AIGenerationButtonState?.restore(restoreButton); - restoreButton.html(originalHtml).prop('disabled', false); - }); - } - - globalThis.queueAttachmentSummary = function(triggerButton = null) { - const applicationId = $('#DetailsViewApplicationId').val(); - const $button = triggerButton ? $(triggerButton) : $('[onclick*="queueAttachmentSummary"]').first(); - const existingHtml = $button.html(); - const promptVersion = globalThis.getSelectedPromptVersion?.() || null; - - if (!applicationId || $button.prop('disabled')) { - return; - } - - $button - .html('Generating...') - .prop('disabled', true); - globalThis.AIGenerationButtonState?.setGenerating($button); - - queueAIGenerationOperation( - () => unity.grantManager.grantApplications.grantApplication.queueAttachmentSummary(applicationId, promptVersion), - 'attachment-summary', - 'Failed to queue AI attachment summary. Please try again.', - $button, - existingHtml - ); - }; - - globalThis.queueApplicationScoring = function(triggerButton = null) { - const applicationId = $('#DetailsViewApplicationId').val(); - const $button = triggerButton ? $(triggerButton) : $('[onclick*="queueApplicationScoring"]').first(); - const existingHtml = $button.html(); - const promptVersion = globalThis.getSelectedPromptVersion?.() || null; - - if (!applicationId || $button.prop('disabled')) { - return; - } - - $button - .html('Generating...') - .prop('disabled', true); - globalThis.AIGenerationButtonState?.setGenerating($button); - - queueAIGenerationOperation( - () => unity.grantManager.grantApplications.grantApplication.queueApplicationScoring(applicationId, promptVersion), - 'application-scoring', - 'Failed to queue AI application scoring. Please try again.', - $button, - existingHtml - ); - }; - - globalThis.refreshPromptToolsOutputs = loadPromptToolsOutputs; - - $(document).on('click', '.prompt-tools-output-copy-btn', async function () { - const targetSelector = $(this).data('target'); - const text = $(targetSelector).val(); - - if (!targetSelector || !text) { - return; - } - - try { - await navigator.clipboard.writeText(text); - abp.notify.success('Copied AI output.'); - } catch { - const output = $(targetSelector); - output.trigger('focus'); - output.trigger('select'); - } - }); - let selectedReviewDetails = null; let renderFormIoToHtml = document.getElementById('RenderFormIoToHtml').value; @@ -531,7 +31,6 @@ $(function () { updateLinksCounters(); renderSubmission(); loadAIAnalysis(); - loadPromptToolsOutputs(); applyTabHeightOffset(); } @@ -819,11 +318,6 @@ $(function () { PubSub.subscribe('refresh_assessment_scores', (msg, data) => { assessmentScoresWidgetManager.refresh(); updateSubtotal(); - loadPromptToolsOutputs(); - }); - - PubSub.subscribe('refresh_chefs_attachment_list', () => { - loadPromptToolsOutputs(); }); PubSub.subscribe('select_application_review', (msg, data) => { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/ai-analysis.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/ai-analysis.js index 8bd0df421a..885a705ca9 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/ai-analysis.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/ai-analysis.js @@ -415,7 +415,6 @@ globalThis.queueApplicationAnalysis = function(triggerButton = null) { const applicationId = $('#DetailsViewApplicationId').val(); const $button = triggerButton ? $(triggerButton) : $('#regenerateApplicationAnalysis'); const existingHtml = $button.html(); - const promptVersion = globalThis.getSelectedPromptVersion?.() || null; const aiAnalysisPollIntervalMs = 15000; const aiAnalysisMaxPollFailures = 3; @@ -439,7 +438,7 @@ globalThis.queueApplicationAnalysis = function(triggerButton = null) { const poll = function() { unity.grantManager.grantApplications.grantApplication - .getAIGenerationStatus(applicationId, 'application-analysis', promptVersion) + .getAIGenerationStatus(applicationId, 'application-analysis') .done(function(request) { aiAnalysisPollFailures = 0; const statusText = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; @@ -479,7 +478,7 @@ globalThis.queueApplicationAnalysis = function(triggerButton = null) { }; unity.grantManager.grantApplications.grantApplication - .queueApplicationAnalysis(applicationId, promptVersion) + .queueApplicationAnalysis(applicationId) .done(function(request) { aiAnalysisPollFailures = 0; stopAIAnalysisPolling(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Swagger/ApplicantProfileDataSchemaFilter.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Swagger/ApplicantProfileDataSchemaFilter.cs index 46a7fedc90..5abe3ef7c7 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Swagger/ApplicantProfileDataSchemaFilter.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Swagger/ApplicantProfileDataSchemaFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; using Unity.GrantManager.ApplicantProfile.ProfileData; @@ -7,11 +7,16 @@ namespace Unity.GrantManager.Swagger { public class ApplicantProfileDataSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { if (context.Type != typeof(ApplicantProfileDataDto)) return; + // OpenAPI.NET v2 exposes IOpenApiSchema (read-only) in filter signatures, + // but the underlying instance is OpenApiSchema. Cast to mutate. + if (schema is not OpenApiSchema mutableSchema) + return; + var subTypes = new Dictionary { ["CONTACTINFO"] = typeof(ApplicantContactInfoDto), @@ -21,18 +26,18 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context) ["PAYMENTINFO"] = typeof(ApplicantPaymentInfoDto) }; - var oneOfSchemas = new List(); + var oneOfSchemas = new List(); foreach (var (_, subType) in subTypes) { var subSchema = context.SchemaGenerator.GenerateSchema(subType, context.SchemaRepository); oneOfSchemas.Add(subSchema); } - schema.OneOf = oneOfSchemas; - schema.Discriminator = new OpenApiDiscriminator + mutableSchema.OneOf = oneOfSchemas; + mutableSchema.Discriminator = new OpenApiDiscriminator { PropertyName = "dataType", - Mapping = new Dictionary() + Mapping = new Dictionary() }; foreach (var (discriminatorValue, subType) in subTypes) @@ -40,10 +45,10 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context) var schemaId = context.SchemaRepository.Schemas.ContainsKey(subType.FullName!) ? subType.FullName! : subType.Name; - schema.Discriminator.Mapping[discriminatorValue] = $"#/components/schemas/{schemaId}"; + mutableSchema.Discriminator.Mapping[discriminatorValue] = new OpenApiSchemaReference(schemaId); } - schema.Description = "Polymorphic data payload. The shape depends on the 'dataType' discriminator (key parameter)."; + mutableSchema.Description = "Polymorphic data payload. The shape depends on the 'dataType' discriminator (key parameter)."; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Unity.GrantManager.Web.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Unity.GrantManager.Web.csproj index dc7d8b01dd..f44d2fc836 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Unity.GrantManager.Web.csproj +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Unity.GrantManager.Web.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager.Web @@ -47,8 +47,8 @@ - - + + all runtime; @@ -59,26 +59,23 @@ buildtransitive - - + + - - - - - - - - - - - - + + + + + + + + + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/ApplicantSubmissionsViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/ApplicantSubmissionsViewComponent.cs index db7b309121..901c16baf1 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/ApplicantSubmissionsViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantSubmissions/ApplicantSubmissionsViewComponent.cs @@ -70,8 +70,8 @@ public async Task InvokeAsync(Guid applicantId) // Map related entities dto.Status = app.ApplicationStatus?.InternalStatus ?? string.Empty; dto.Category = app.ApplicationForm?.Category ?? string.Empty; - dto.SubStatusDisplayValue = MapSubstatusDisplayValue(dto.SubStatus); - dto.DeclineRational = MapDeclineRationalDisplayValue(dto.DeclineRational); + dto.SubStatusDisplayValue = MapSubstatusDisplayValue(dto.SubStatus ?? string.Empty); + dto.DeclineRational = MapDeclineRationalDisplayValue(dto.DeclineRational ?? string.Empty); dto.Applicant = app.Applicant != null ? _objectMapper.Map(app.Applicant) : new GrantApplicationApplicantDto(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs index 42ae522e40..aafb08a420 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicationBreadcrumbWidget/ApplicationBreadcrumbWidget.cs @@ -27,7 +27,7 @@ public async Task InvokeAsync(Guid applicationId) return View(new ApplicationBreadcrumbWidgetViewModel() { ApplicantId = applicationApplicant.ApplicantId, - ApplicantName = applicationApplicant.ApplicantName, + ApplicantName = applicationApplicant.ApplicantName ?? string.Empty, ApplicationStatus = applicationApplicant.ApplicationStatus, ReferenceNo = applicationApplicant.ApplicationReferenceNo, diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentScoresWidget/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentScoresWidget/Default.js index 1e7dd26748..b697de046a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentScoresWidget/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/AssessmentScoresWidget/Default.js @@ -584,7 +584,6 @@ function queueApplicationScoring(triggerButton = null) { const applicationId = $('#DetailsViewApplicationId').val(); const $button = triggerButton ? $(triggerButton) : $('#regenerateAiScoresheetBtn'); const existingHtml = $button.html(); - const promptVersion = globalThis.getSelectedPromptVersion?.() || null; const aiGenerationPollIntervalMs = 15000; let aiGenerationPollTimeoutId = null; @@ -608,7 +607,7 @@ function queueApplicationScoring(triggerButton = null) { const poll = function () { unity.grantManager.grantApplications.grantApplication - .getAIGenerationStatus(applicationId, 'application-scoring', promptVersion) + .getAIGenerationStatus(applicationId, 'application-scoring') .done(function (request) { const status = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; @@ -635,8 +634,8 @@ function queueApplicationScoring(triggerButton = null) { }); }; - unity.grantManager.grantApplications.applicationScoring - .queueApplicationScoring(applicationId, promptVersion) + unity.grantManager.grantApplications.grantApplication + .queueApplicationScoring(applicationId) .done(function (request) { const status = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.css b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.css index d3008b860e..cb02550ca9 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.css +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.css @@ -90,7 +90,7 @@ } #ChefsAttachmentsTable td.ai-summary-cell { - padding: 0 !important; + padding: 0; } #ChefsAttachmentsTable .ai-summary-content { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.js index 03191486c5..969a7e5382 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ChefsAttachments/ChefsAttachments.js @@ -1,20 +1,19 @@ // Note: File depends on Unity.GrantManager.Web\Views\Shared\Components\_Shared\Attachments.js $(function () { - globalThis.queueAttachmentSummary = function(triggerButton = null) { + globalThis.queueAttachmentSummary = function (triggerButton = null) { $('#generateAiSummaries') .data('trigger-button', triggerButton || null) .trigger('click'); }; - const downloadAll = $('#downloadSelected'); + const downloadAll = $('#downloadAll'); const dt = $('#ChefsAttachmentsTable'); let chefsDataTable; - let selectedAtttachments = []; + let selectedAttachmentIds = []; const nullPlaceholder = '—'; let inputAction = function (requestData, dataTableSettings) { - const urlParams = new URL(window.location.toLocaleString()) - .searchParams; + const urlParams = new URL(globalThis.location.toLocaleString()).searchParams; const applicationId = urlParams.get('ApplicationId'); return applicationId; }; @@ -31,15 +30,10 @@ $(function () { }); }, 10); - if (result.length === 0 || selectedAtttachments.length === 0) { - $(downloadAll).prop('disabled', true); + $(downloadAll).prop('disabled', result.length === 0); + selectedAttachmentIds = []; + setGenerateSummariesEnabled(); - if (document.getElementById('generateAiSummaries')) { - $generateAISummariesButton.prop('disabled', true); - } - } - - // Check if any attachments have AI summaries and enable/disable toggle button const hasAISummaries = result.some( (item) => item.aiSummary && item.aiSummary.trim() !== '' ); @@ -49,7 +43,7 @@ $(function () { if (!hasAISummaries) { $toggleButton.attr('title', 'No AI summaries available'); } else { - $toggleButton.attr('title', 'Toggle AI Summaries'); + $toggleButton.attr('title', 'Show AI Summaries'); } } } @@ -67,6 +61,35 @@ $(function () { ]; } + function setGenerateSummariesEnabled() { + $('#generateAiSummaries').prop('disabled', selectedAttachmentIds.length === 0); + } + + function setSelectAllState() { + const totalCheckboxes = $('#ChefsAttachmentsTable .chkbox').length; + const selectedCheckboxes = $('#ChefsAttachmentsTable .chkbox:checked').length; + $('.select-all-chefs-files').prop( + 'checked', + totalCheckboxes > 0 && selectedCheckboxes === totalCheckboxes + ); + } + + function resetAttachmentSelection() { + selectedAttachmentIds = []; + chefsDataTable.rows().deselect(); + chefsDataTable.$('.chkbox').prop('checked', false); + $('.select-all-chefs-files').prop('checked', false); + setGenerateSummariesEnabled(); + } + + function setAllAttachmentSelections(isSelected) { + if (isSelected) { + chefsDataTable.rows({ page: 'current' }).select(); + } else { + chefsDataTable.rows({ page: 'current' }).deselect(); + } + } + function getChefsFileNameColumn() { return { title: 'Document Name', @@ -91,8 +114,6 @@ $(function () { }; } - - let formatItems = function (items) { const newData = items.map((item, index) => { return { @@ -126,22 +147,6 @@ $(function () { responseCallback ), columnDefs: getColumns(), - createdRow: function (row, data, dataIndex) { - if (data.aiSummary) { - let summaryRow = $( - '' - ) - .append($('')) - .append( - $( - '' - ).text(data.aiSummary) - ); - $(row).after(summaryRow); - } - }, externalFilterButtonId: 'btn-toggle-filter-submissions', }) ); @@ -152,74 +157,56 @@ $(function () { chefsDataTable.ajax.reload(); }); - //Generate AI summaries for attachments + // Generate AI summaries for the current application attachments. const $generateAISummariesButton = $('#generateAiSummaries'); if ($generateAISummariesButton.length > 0) { - function resetAttachmentSelectionState() { - selectedAtttachments = []; - $('.select-all-chefs-files').prop('checked', false); - chefsDataTable.$('.chkbox').prop('checked', false); - $(downloadAll).prop('disabled', true); - $generateAISummariesButton.prop('disabled', true); - } - $generateAISummariesButton.on('click', function () { const $button = $(this); const triggerButton = $button.data('trigger-button'); const $activeButton = triggerButton ? $(triggerButton) : $button; - const rowsToProcess = triggerButton - ? chefsDataTable.rows().data() - : chefsDataTable.rows({ selected: true }).data(); - const promptVersion = globalThis.getSelectedPromptVersion?.() || null; + const rows = triggerButton + ? chefsDataTable.rows().data().toArray() + : chefsDataTable.rows({ selected: true }).data().toArray(); + const summaryAttachmentIds = rows.map((row) => row.id); $button.removeData('trigger-button'); - if (rowsToProcess.length === 0) { + if (summaryAttachmentIds.length === 0) { abp.message.warn( triggerButton - ? 'No attachments were found to generate summaries for.' - : 'Please select at least one attachment to generate summaries.' + ? 'No attachments were found to generate summaries.' + : 'Select at least one attachment to generate summaries.' ); return; } - const attachmentIds = rowsToProcess.toArray().map((row) => row.id); - const existingHTML = $activeButton.html(); - // Call the backend API + $activeButton + .html( + 'Generating...' + ) + .prop('disabled', true); + globalThis.AIGenerationButtonState?.setGenerating($activeButton); + $.ajax({ - url: - '/api/app/attachment-summary/generate-attachment-summaries' + - '?promptVersion=' + - encodeURIComponent(promptVersion || ''), - data: JSON.stringify(attachmentIds), + url: '/api/app/attachment-summary/generate-attachment-summaries', + data: JSON.stringify(summaryAttachmentIds), contentType: 'application/json', type: 'POST', - beforeSend: function () { - $activeButton - .html( - 'Queueing...' - ) - .prop('disabled', true); - }, - success: function (summaries) { - abp.notify.success( - 'AI summaries queued for ' + - summaries.length + - ' attachment(s). Refresh later to see updated results.' - ); - - resetAttachmentSelectionState(); - + success: function () { + resetAttachmentSelection(); + chefsDataTable.ajax.reload(); + abp.notify.success('AI summaries generated successfully.'); + globalThis.AIGenerationButtonState?.restore($activeButton); $activeButton.html(existingHTML).prop('disabled', false); }, error: function (error) { console.error('Error generating AI summaries:', error); - abp.notify.error( - 'An error occurred while queueing AI summaries. Please try again.' - ); + abp.message.error('An error occurred while generating AI summaries. Please try again.'); + globalThis.AIGenerationButtonState?.restore($activeButton); $activeButton.html(existingHTML).prop('disabled', false); + setGenerateSummariesEnabled(); }, }); }); @@ -233,80 +220,64 @@ $(function () { $toggleAllAISummariesButton.on('click', function () { const $button = $(this); const $icon = $button.find('i'); - const $text = $button.contents().filter(function () { - return this.nodeType === 3; - }); + const $label = $button.find('.toggle-ai-summaries-label'); - // Don't do anything if button is disabled if ($button.prop('disabled')) { return; } if (allAISummariesExpanded) { - // Collapse all chefsDataTable.rows().every(function () { const row = this; if (row.child.isShown()) { const $childRow = $(row.child()); const $summaryRow = $childRow.find('.ai-summary-row'); - // Add fade-out class to the summary row $summaryRow.removeClass('fade-in').addClass('fade-out'); - // Wait for animation to complete before hiding setTimeout(function () { row.child.hide(); $(row.node()).removeClass('shown'); $summaryRow.removeClass('fade-out'); - }, 500); // Match animation duration + }, 500); } }); $icon.removeClass('fa-chevron-up').addClass('fa-chevron-down'); - $text.replaceWith('Show Summaries'); + $label.text('Show Summaries'); $button.attr('title', 'Show AI Summaries'); allAISummariesExpanded = false; } else { - // Expand all chefsDataTable.rows().every(function () { const row = this; const rowData = row.data(); - // Only expand if there's an AI summary if (rowData.aiSummary && rowData.aiSummary.trim() !== '') { - // Create the summary HTML const summaryHtml = formatAISummary(rowData); - // Show the child row - row.child(summaryHtml).show(); + row.child(summaryHtml, 'ai-summary-cell').show(); $(row.node()).addClass('shown'); - // Add fade-in animation after DOM is ready setTimeout(function () { const $childRow = $(row.child()); - $childRow - .find('.ai-summary-row') - .addClass('fade-in'); + $childRow.find('.ai-summary-row').addClass('fade-in'); }, 10); } }); $icon.removeClass('fa-chevron-down').addClass('fa-chevron-up'); - $text.replaceWith('Hide Summaries'); + $label.text('Hide Summaries'); $button.attr('title', 'Hide AI Summaries'); allAISummariesExpanded = true; } }); } - // Reset AI summary expansion state when table is reloaded chefsDataTable.on('draw.dt', function () { if (allAISummariesExpanded) { const $button = $('#toggleAllAISummaries'); const $icon = $button.find('i'); - const $text = $button.contents().filter(function () { - return this.nodeType === 3; - }); + const $label = $button.find('.toggle-ai-summaries-label'); $icon.removeClass('fa-chevron-up').addClass('fa-chevron-down'); - $text.replaceWith('Show Summaries'); + $label.text('Show Summaries'); $button.attr('title', 'Show AI Summaries'); allAISummariesExpanded = false; } @@ -326,76 +297,42 @@ $(function () { ); } - chefsDataTable.on('select', function (e, dt, type, indexes) { - if (indexes?.length) { - indexes.forEach((index) => { - $(chefsDataTable.row(index).node()).find('.chkbox').prop('checked', true); - if (chefsDataTable.$('.chkbox:checked').length == chefsDataTable.$('.chkbox').length) { - $('.select-all-chefs-files').prop('checked', true); - } - selectAttachment(type, index, 'select_chefs_file'); - }); - } + $(document).on('click', '.select-all-chefs-files', function () { + setAllAttachmentSelections($(this).is(':checked')); }); - chefsDataTable.on('deselect', function (e, dt, type, indexes) { - if (indexes?.length) { - indexes.forEach((index) => { - $(chefsDataTable.row(index).node()).find('.chkbox').prop('checked', false); - if (chefsDataTable.$('.chkbox:checked').length != chefsDataTable.$('.chkbox').length) { - $('.select-all-chefs-files').prop('checked', false); - } - selectAttachment(type, index, 'deselect_chefs_file'); - }); + chefsDataTable.on('select', function (e, dt, type, indexes) { + if (type !== 'row') { + return; } - }); - function selectAttachment(type, indexes, action) { - if (type === 'row') { - let data = chefsDataTable.row(indexes).data(); - PubSub.publish(action, data); + indexes.forEach((index) => { + const data = chefsDataTable.row(index).data(); + $('#row_' + index).prop('checked', true); - if (action == 'select_chefs_file') { - const found = selectedAtttachments.some( - (item) => item.chefsFileId === data.chefsFileId - ); - if (!found) { - selectedAtttachments.push({ - FormSubmissionId: data.chefsSubmissionId, - ChefsFileId: data.chefsFileId, - Filename: data.fileName, - }); - } - } else if (action == 'deselect_chefs_file') { - const filtedItems = selectedAtttachments.filter( - (item) => item.ChefsFileId !== data.chefsFileId - ); - selectedAtttachments = filtedItems; - } - - if (selectedAtttachments.length > 0) { - $(downloadAll).prop('disabled', false); - } else { - $(downloadAll).prop('disabled', true); + if (data?.id && !selectedAttachmentIds.includes(data.id)) { + selectedAttachmentIds.push(data.id); } + }); + setGenerateSummariesEnabled(); + setSelectAllState(); + }); - if ( - document.getElementById('generateAiSummaries') && - selectedAtttachments.length > 0 - ) { - $generateAISummariesButton.prop('disabled', false); - } else { - $generateAISummariesButton.prop('disabled', true); - } + chefsDataTable.on('deselect', function (e, dt, type, indexes) { + if (type !== 'row') { + return; } - } - $('.select-all-chefs-files').on('click', function () { - if ($(this).is(':checked')) { - chefsDataTable.rows({ page: 'current' }).select(); - } else { - chefsDataTable.rows({ page: 'current' }).deselect(); - } + indexes.forEach((index) => { + const data = chefsDataTable.row(index).data(); + $('#row_' + index).prop('checked', false); + + if (data?.id) { + selectedAttachmentIds = selectedAttachmentIds.filter((id) => id !== data.id); + } + }); + setGenerateSummariesEnabled(); + setSelectAllState(); }); $('#resyncSubmissionAttachments').on('click', function () { @@ -406,9 +343,7 @@ $(function () { unity.grantManager.attachments.attachment .resyncSubmissionAttachments(applicationId) .done(function () { - abp.notify.success( - 'Submission Attachment/s has been resynced.' - ); + abp.notify.success('Submission Attachment/s has been resynced.'); chefsDataTable.ajax.reload(); chefsDataTable.columns.adjust(); }); @@ -427,17 +362,19 @@ $(function () { const _this = $(this); const existingHTML = _this.html(); const zip = new JSZip(); - const tempFiles = selectedAtttachments; + const tempFiles = chefsDataTable.rows().data().toArray().map((row) => ({ + FormSubmissionId: row.chefsSubmissionId, + ChefsFileId: row.chefsFileId, + Filename: row.fileName, + })); if (tempFiles.length > 0) { - //Calls an endpoint $.ajax({ url: '/api/app/attachment/chefs/download-all', data: JSON.stringify(tempFiles), contentType: 'application/json', type: 'POST', beforeSend: function () { - //Add loading spinner $(_this) .html( '
Downloading...
' @@ -451,9 +388,7 @@ $(function () { }); }); - zip.generateAsync({ type: 'blob' }).then(function ( - content - ) { + zip.generateAsync({ type: 'blob' }).then(function (content) { const link = document.createElement('a'); link.href = URL.createObjectURL(content); link.download = `${refNo}-All_Attachments.zip`; @@ -464,7 +399,6 @@ $(function () { '', 'The files have been downloaded successfully.' ); - //show original HTML and enable $(_this).html(existingHTML).prop('disabled', false); }, error: function (error) { @@ -493,35 +427,35 @@ function getChefsFileDownloadColumn() { className: 'text-nowrap', render: function (data, type, full, meta) { let submissionId = encodeURIComponent(full.chefsSubmissionId); - let fileId = encodeURIComponent(data); - let fileName = full.fileName; - let displayName = full.displayName || full.fileName; + let fileId = encodeURIComponent(data); + let fileName = full.fileName; + let displayName = full.displayName || full.fileName; let html = ''; return html; }, @@ -547,7 +481,6 @@ function downloadChefsFile(event) { chefsFileName, }); - //Calls an endpoint $.ajax({ url: '/api/app/attachment/chefs/' + @@ -558,7 +491,6 @@ function downloadChefsFile(event) { chefsFileName, type: 'GET', success: function (data) { - // Download file by navigating to the endpoint const downloadUrl = '/api/app/attachment/chefs/' + encodeURIComponent(chefsSubmissionId) + @@ -567,7 +499,6 @@ function downloadChefsFile(event) { '/' + encodeURIComponent(chefsFileName); - // Create a temporary link and trigger download const link = document.createElement('a'); link.href = downloadUrl; link.download = chefsFileName; @@ -575,10 +506,7 @@ function downloadChefsFile(event) { document.body.appendChild(link); link.click(); document.body.removeChild(link); - abp.notify.success( - '', - 'The file has been downloaded successfully.' - ); + abp.notify.success('', 'The file has been downloaded successfully.'); }, error: function (error) { console.log('Error downloading CHEFS file:', error); @@ -627,4 +555,4 @@ function showChefsAPIAccessError() { confirmButton: 'btn btn-primary', }, }); -} \ No newline at end of file +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js index 375a71bf30..7a51887572 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js @@ -78,7 +78,7 @@ defaultValues.emailFrom = UIElements.inputOriginalEmailFrom.val(); defaultValues.emailCC = UIElements.inputOriginalEmailCC.val() || ''; defaultValues.emailBCC = UIElements.inputOriginalEmailBCC.val() || ''; - toastr.options.positionClass = 'toast-top-center'; + if (window.toastr) { toastr.options.positionClass = 'toast-top-center'; } initTemplateDetails(); $('#templateTextContainer').hide(); UIElements.btnSave.hide(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js index c9d3e5bbe8..569cc89c97 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js @@ -34,7 +34,7 @@ toggleParentFormSection(); toggleDefaultPaymentGroupRow(UIElements.payable.is(':checked')); - toastr.options.positionClass = 'toast-top-center'; + if (window.toastr) { toastr.options.positionClass = 'toast-top-center'; } UIElements.btnSave.prop('disabled', true); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ReviewList/ReviewList.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ReviewList/ReviewList.js index 257407605c..0da7f980ce 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ReviewList/ReviewList.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ReviewList/ReviewList.js @@ -455,98 +455,97 @@ function unityWorkflowButtonAction(e, dt, button, config) { } } -function generateAiButtonAction(e, dt, button, config) { - const $button = button?.node ? $(button.node) : null; - const promptVersion = globalThis.getSelectedPromptVersion?.() || null; - const aiGenerationPollIntervalMs = 15000; - let aiGenerationPollTimeoutId = null; - - if ($button?.length) { - $button.prop('disabled', true); - $button.html('Generating...'); - globalThis.AIGenerationButtonState?.setGenerating($button); - } - - const stopPolling = function () { - if (aiGenerationPollTimeoutId) { - clearTimeout(aiGenerationPollTimeoutId); - aiGenerationPollTimeoutId = null; - } - }; - - const poll = function () { - unity.grantManager.grantApplications.grantApplication - .getAIGenerationStatus(pageApplicationId, 'application-scoring', promptVersion) - .done(function (request) { - const status = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; - - if (status === 'Failed') { - stopPolling(); - abp.message.error(request?.failureReason || 'AI scoring failed.'); - if ($button?.length) { - globalThis.AIGenerationButtonState?.restore($button); - $button.prop('disabled', false); - $button.html(generateAiButtonText(null, null, null)); - } - return; - } - - if (!request || request.isActive === false || status === 'Completed') { - stopPolling(); - setReviewListAiButtonCompleted($button); - refreshReviewListAfterAiScoring(); - return; - } - - aiGenerationPollTimeoutId = setTimeout(poll, aiGenerationPollIntervalMs); - }) - .fail(function () { - aiGenerationPollTimeoutId = setTimeout(poll, aiGenerationPollIntervalMs); - }); - }; - - unity.grantManager.grantApplications.grantApplication.queueApplicationScoring(pageApplicationId, promptVersion) - .done(function (request) { - const status = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; - - if (status === 'Completed') { - setReviewListAiButtonCompleted($button); - refreshReviewListAfterAiScoring(); - return; - } - - aiGenerationPollTimeoutId = setTimeout(poll, 500); - }) - .fail(function () { - stopPolling(); - abp.message.error('Failed to queue AI scoring. Please try again.'); - if ($button?.length) { - globalThis.AIGenerationButtonState?.restore($button); - $button.prop('disabled', false); - $button.html(generateAiButtonText(null, null, null)); - } - }) - ; -} - -function setReviewListAiButtonCompleted($button) { - if (!$button?.length) { - return; - } - - globalThis.AIGenerationButtonState?.setCompleted($button); - $button.html('Completed').prop('disabled', true); -} - -function refreshReviewListAfterAiScoring() { - PubSub.publish('refresh_review_list', pageApplicationId); - PubSub.publish('refresh_assessment_scores', null); -} - -function executeAssessmentAction(assessmentId, triggerAction) { - unity.grantManager.assessments.assessment.executeAssessmentAction(assessmentId, triggerAction, {}) - .then(function (result) { - PubSub.publish('assessment_action_completed'); +function generateAiButtonAction(e, dt, button, config) { + const $button = button?.node ? $(button.node) : null; + const aiGenerationPollIntervalMs = 15000; + let aiGenerationPollTimeoutId = null; + + if ($button?.length) { + $button.prop('disabled', true); + $button.html('Generating...'); + globalThis.AIGenerationButtonState?.setGenerating($button); + } + + const stopPolling = function () { + if (aiGenerationPollTimeoutId) { + clearTimeout(aiGenerationPollTimeoutId); + aiGenerationPollTimeoutId = null; + } + }; + + const poll = function () { + unity.grantManager.grantApplications.grantApplication + .getAIGenerationStatus(pageApplicationId, 'application-scoring') + .done(function (request) { + const status = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; + + if (status === 'Failed') { + stopPolling(); + abp.message.error(request?.failureReason || 'AI scoring failed.'); + if ($button?.length) { + globalThis.AIGenerationButtonState?.restore($button); + $button.prop('disabled', false); + $button.html(generateAiButtonText(null, null, null)); + } + return; + } + + if (!request || request.isActive === false || status === 'Completed') { + stopPolling(); + setReviewListAiButtonCompleted($button); + refreshReviewListAfterAiScoring(); + return; + } + + aiGenerationPollTimeoutId = setTimeout(poll, aiGenerationPollIntervalMs); + }) + .fail(function () { + aiGenerationPollTimeoutId = setTimeout(poll, aiGenerationPollIntervalMs); + }); + }; + + unity.grantManager.grantApplications.grantApplication.queueApplicationScoring(pageApplicationId) + .done(function (request) { + const status = globalThis.AIGenerationButtonState?.resolveStatus(request?.status) ?? ''; + + if (status === 'Completed') { + setReviewListAiButtonCompleted($button); + refreshReviewListAfterAiScoring(); + return; + } + + aiGenerationPollTimeoutId = setTimeout(poll, 500); + }) + .fail(function () { + stopPolling(); + abp.message.error('Failed to queue AI scoring. Please try again.'); + if ($button?.length) { + globalThis.AIGenerationButtonState?.restore($button); + $button.prop('disabled', false); + $button.html(generateAiButtonText(null, null, null)); + } + }) + ; +} + +function setReviewListAiButtonCompleted($button) { + if (!$button?.length) { + return; + } + + globalThis.AIGenerationButtonState?.setCompleted($button); + $button.html('Completed').prop('disabled', true); +} + +function refreshReviewListAfterAiScoring() { + PubSub.publish('refresh_review_list', pageApplicationId); + PubSub.publish('refresh_assessment_scores', null); +} + +function executeAssessmentAction(assessmentId, triggerAction) { + unity.grantManager.assessments.assessment.executeAssessmentAction(assessmentId, triggerAction, {}) + .then(function (result) { + PubSub.publish('assessment_action_completed'); PubSub.publish('refresh_review_list', assessmentId); abp.notify.success( "Completed Successfully", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json index b74c91d2f4..bca4bf77b1 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json @@ -152,7 +152,8 @@ "Defaults": { "Provider": "OpenAI", "Profile": "Gpt4oMini", - "PromptVersion": "v1" + "PromptVersion": "v1", + "ExecutionMode": "Sequential" }, "AttachmentSummary": { "MaxCompletionTokens": 2000 @@ -183,4 +184,4 @@ "EnablePromptFileLog": false } } -} \ No newline at end of file +} diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AIExecutionModeResolverTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AIExecutionModeResolverTests.cs new file mode 100644 index 0000000000..116a8b29ec --- /dev/null +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AIExecutionModeResolverTests.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.Configuration; +using Shouldly; +using System.Collections.Generic; +using Unity.AI.Operations; +using Unity.AI.Prompts; +using Xunit; + +namespace Unity.GrantManager.AI.Operations; + +public class AIExecutionModeResolverTests +{ + [Fact] + public void ResolveMode_Uses_Operation_Override_Before_Default() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + ["Azure:Operations:Defaults:ExecutionMode"] = "Parallel", + [$"Azure:Operations:{AIPromptTypes.ApplicationScoring}:ExecutionMode"] = "Batch" + }) + .Build(); + + var resolver = new AIExecutionModeResolver(configuration); + + resolver.ResolveMode(AIPromptTypes.ApplicationScoring).ShouldBe(AIExecutionMode.Batch); + resolver.ResolveMode(AIPromptTypes.AttachmentSummary).ShouldBe(AIExecutionMode.Parallel); + } +} diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AIExecutionStrategyTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AIExecutionStrategyTests.cs new file mode 100644 index 0000000000..27343459b7 --- /dev/null +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AIExecutionStrategyTests.cs @@ -0,0 +1,39 @@ +using Shouldly; +using System.Collections.Generic; +using System.Threading.Tasks; +using Unity.AI.Operations; +using Xunit; + +namespace Unity.GrantManager.AI.Operations; + +public class AIExecutionStrategyTests +{ + [Fact] + public async Task Batch_Uses_Single_Batch_Operation() + { + var itemCalls = 0; + var batchCalls = 0; + IReadOnlyCollection? batchItems = null; + + var results = await AIExecutionStrategy.RunAsync( + [1, 2, 3], + AIExecutionMode.Batch, + item => + { + itemCalls++; + return Task.FromResult(item); + }, + items => + { + batchCalls++; + batchItems = items; + return Task.FromResult(new List { 6 }); + }); + + itemCalls.ShouldBe(0); + batchCalls.ShouldBe(1); + batchItems.ShouldNotBeNull(); + batchItems.Count.ShouldBe(3); + results.ShouldBe([6]); + } +} diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AttachmentSummaryServiceTests.cs b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AttachmentSummaryServiceTests.cs index 90d79cf6df..5d556e0d1a 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AttachmentSummaryServiceTests.cs +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/AI/Operations/AttachmentSummaryServiceTests.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging.Abstractions; using NSubstitute; using Shouldly; @@ -59,6 +60,7 @@ public async Task GenerateAndSaveAsync_Uses_Streamed_Attachment_Text() streamProvider, textExtractionService, aiService, + new AIExecutionModeResolver(new ConfigurationBuilder().Build()), NullLogger.Instance); var result = await service.GenerateAndSaveAsync(attachmentId, "v1"); diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Unity.GrantManager.Application.Tests.csproj b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Unity.GrantManager.Application.Tests.csproj index f533ffd413..8361545053 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Unity.GrantManager.Application.Tests.csproj +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Application.Tests/Unity.GrantManager.Application.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager @@ -20,11 +20,9 @@
- - - - + +
diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Domain.Tests/Unity.GrantManager.Domain.Tests.csproj b/applications/Unity.GrantManager/test/Unity.GrantManager.Domain.Tests/Unity.GrantManager.Domain.Tests.csproj index 35791efbcd..950674c8f6 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Domain.Tests/Unity.GrantManager.Domain.Tests.csproj +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Domain.Tests/Unity.GrantManager.Domain.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager @@ -13,10 +13,10 @@
- - - + + + diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.EntityFrameworkCore.Tests/Unity.GrantManager.EntityFrameworkCore.Tests.csproj b/applications/Unity.GrantManager/test/Unity.GrantManager.EntityFrameworkCore.Tests/Unity.GrantManager.EntityFrameworkCore.Tests.csproj index 377f8beb4e..a86e0eca24 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.EntityFrameworkCore.Tests/Unity.GrantManager.EntityFrameworkCore.Tests.csproj +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.EntityFrameworkCore.Tests/Unity.GrantManager.EntityFrameworkCore.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Unity.GrantManager @@ -11,12 +11,12 @@ - - - - - - + + + + + + diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.TestBase/Unity.GrantManager.TestBase.csproj b/applications/Unity.GrantManager/test/Unity.GrantManager.TestBase/Unity.GrantManager.TestBase.csproj index f809072d07..bf28c1e6ac 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.TestBase/Unity.GrantManager.TestBase.csproj +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.TestBase/Unity.GrantManager.TestBase.csproj @@ -1,26 +1,24 @@ - + - net9.0 + net10.0 enable Unity.GrantManager - - - - - - - - - - - - + + + + + + + + + + diff --git a/applications/Unity.GrantManager/test/Unity.GrantManager.Web.Tests/Unity.GrantManager.Web.Tests.csproj b/applications/Unity.GrantManager/test/Unity.GrantManager.Web.Tests/Unity.GrantManager.Web.Tests.csproj index 608f44b106..e3e22f4e0a 100644 --- a/applications/Unity.GrantManager/test/Unity.GrantManager.Web.Tests/Unity.GrantManager.Web.Tests.csproj +++ b/applications/Unity.GrantManager/test/Unity.GrantManager.Web.Tests/Unity.GrantManager.Web.Tests.csproj @@ -1,9 +1,9 @@ - + - net9.0 + net10.0 enable Exe Unity.GrantManager @@ -21,18 +21,17 @@ - - + - - - - - + + + + + - +