Compare commits
4 Commits
e960c02cd4
...
feat/read-
| Author | SHA1 | Date | |
|---|---|---|---|
| 796b233ba4 | |||
|
|
1e2e018f7f | ||
|
|
69afea012b | ||
|
|
85e0bc3400 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -365,8 +365,3 @@ FodyWeavers.xsd
|
||||
/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/.vscode
|
||||
/EnvelopeGenerator.Tests.Application/Services/BugFixTests.cs
|
||||
/EnvelopeGenerator.Tests.Application/annotations.json
|
||||
/EnvelopeGenerator.Server/EnvelopeGenerator.Server/TekH - SoftHSM Test.md
|
||||
/EnvelopeGenerator.Server/EnvelopeGenerator.Server/tekh_softHSM_test.md
|
||||
/EnvelopeGenerator.Server/EnvelopeGenerator.Server/publish-output
|
||||
/EnvelopeGenerator.Server/EnvelopeGenerator.Server/tekh_softHSM_test.md
|
||||
/ignore/EnvelopeGenerator.Form
|
||||
|
||||
316
AGENTS.md
316
AGENTS.md
@@ -1,316 +0,0 @@
|
||||
# EnvelopeGenerator - Agent Guide
|
||||
|
||||
## Must Read First
|
||||
- **`COPILOT_CONTEXT.md`** - Architecture, coordinate systems, migration status
|
||||
- **`FORM_APPLICATION_CONTEXT.md`** - Legacy VB.NET features to migrate
|
||||
|
||||
---
|
||||
|
||||
## Documentation Catalog
|
||||
|
||||
This section explains every markdown file in the repo: what it contains, why it exists, and when you need it. Read this before deciding which file to open.
|
||||
|
||||
### Core Architecture Docs (Active — Always Relevant)
|
||||
|
||||
#### `AGENTS.md` ← you are here
|
||||
**What:** Authoritative agent/copilot onboarding guide. Covers project structure, route table, render mode rules, coordinate system, API gaps, and common mistakes.
|
||||
**Why it exists:** Single source of truth for agents so they don't re-derive architecture from code on every session.
|
||||
**When you need it:** Always. Read first on every session.
|
||||
**Maintenance:** Update whenever project structure, routes, render modes, or naming conventions change.
|
||||
|
||||
#### `COPILOT_CONTEXT.md`
|
||||
**What:** Deep-dive architecture reference. Covers the full Blazor Auto hybrid setup, authentication flows (JWT + cookies, per-envelope receiver tokens), service registration patterns, coordinate system proof, and an explicit "prefer Server/Server.Client over old WebUI/ReceiverUI" rule.
|
||||
**Why it exists:** Prevents agents from re-deriving or misinterpreting the hybrid SSR+WASM architecture. Also documents coordinate system evidence to prevent regressions (inches vs. points vs. pixels).
|
||||
**When you need it:**
|
||||
- Implementing any new page or service
|
||||
- Debugging auth/cookie issues
|
||||
- Any coordinate conversion question
|
||||
- Unsure which project a new file should go in
|
||||
**Maintenance:** Update when render mode assignments change, new auth schemes are added, or the coordinate system is touched.
|
||||
|
||||
#### `FORM_APPLICATION_CONTEXT.md`
|
||||
**What:** Comprehensive reverse-engineering of the legacy VB.NET WinForms app (`EnvelopeGenerator.Form`). Documents every form (frmMain, frmEnvelopeEditor, frmFieldEditor, etc.), their UI layout, toolbar actions, data models, coordinate system, and a feature-by-feature migration mapping table to `EnvelopeGenerator.Server`.
|
||||
**Why it exists:** The WinForms app is the functional specification for the sender-side web UI. It documents the full intended workflow that is being migrated to Blazor — especially the envelope creation, signature field placement, and dashboard features that are not yet implemented.
|
||||
**When you need it:**
|
||||
- Implementing any sender-side feature (`/sender`, `/sender/editor`, `/sender/envelope/{id}`)
|
||||
- Understanding what a specific toolbar button or form should do
|
||||
- Designing API endpoints for sender workflow
|
||||
- Checking coordinate system behavior (INCHES proof is here)
|
||||
**Maintenance:** Update the mapping table as features are implemented (change `❌ Not implemented` → `✅ Exists`). Do not rename `ReceiverUI` back — it was the old project name; current target is `EnvelopeGenerator.Server`.
|
||||
|
||||
#### `RECEIVER_PDF_VIEWER_CONTEXT.md`
|
||||
**What:** Detailed technical reference for the receiver-side PDF viewer (`EnvelopeReceiverPage.razor`). Documents the PDF.js integration, signature button rendering, JS interop API (`window.pdfViewer`), signature capture flow, HiDPI/zoom/thumbnail config, and the full component lifecycle.
|
||||
**Why it exists:** The receiver PDF viewer is the most complex component in the codebase. This doc prevents agents from misunderstanding the JS↔Blazor boundary, re-implementing already-solved problems (HiDPI, zoom, signature caching), or breaking the signing flow.
|
||||
**When you need it:**
|
||||
- Working on `EnvelopeReceiverPage.razor` or `pdf-viewer.js`
|
||||
- Adding new signature field rendering logic
|
||||
- Debugging signature rendering, zoom, or thumbnail issues
|
||||
- Implementing sender-side PDF.js overlay (signature field placement) — the receiver side is the reference implementation
|
||||
**Maintenance:** Update when `pdf-viewer.js` API changes, new JS interop functions are added, or the signing flow is modified.
|
||||
|
||||
---
|
||||
|
||||
### Deployment Docs
|
||||
|
||||
#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/README.md`
|
||||
**What:** IIS publish and deployment guide for `EnvelopeGenerator.Server`. Covers why self-contained publish is required (WASM assembly version strictness), the exact `dotnet publish` command, IIS Application Pool settings (`No Managed Code`), directory structure after publish, and common deployment errors.
|
||||
**Why it exists:** Blazor Auto (Server + WASM hybrid) has non-obvious deployment requirements that differ from a standard ASP.NET Core app. Forgetting self-contained publish or using the wrong app pool will break WASM loading in production.
|
||||
**When you need it:**
|
||||
- Deploying to IIS for the first time
|
||||
- Troubleshooting 500 errors on production after deploy
|
||||
- Setting up a new deployment environment
|
||||
**Maintenance:** Update if the publish target, IIS config, or runtime version changes.
|
||||
|
||||
---
|
||||
|
||||
## Active Architecture (Post-Migration)
|
||||
|
||||
**Frontend:** Blazor Auto (Server+WASM hybrid)
|
||||
- **EnvelopeGenerator.Server** (Server): `@rendermode InteractiveServer` - PDF viewers requiring DevExpress backend
|
||||
- **EnvelopeGenerator.Server.Client** (WASM): `@rendermode InteractiveWebAssembly` - Login, dashboards, business logic
|
||||
|
||||
**Backend + API Host:** `EnvelopeGenerator.Server` (ASP.NET Core 8.0, merged Blazor + Web API host)
|
||||
|
||||
**Proxy:** YARP in `EnvelopeGenerator.Server` is used for external integrations (for example AuthHub forwarding), not for routing app APIs to `EnvelopeGenerator.API`.
|
||||
|
||||
### Deprecated Projects - DO NOT USE
|
||||
- `EnvelopeGenerator.ReceiverUI` - Pure WASM (migrated to Server)
|
||||
- `EnvelopeGenerator.Web` - Razor Pages (replaced by Server)
|
||||
- **VB.NET projects** (`Form`, `Service`, `BBTests`) - Legacy, read-only for reference
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Run Active Host
|
||||
```powershell
|
||||
# Terminal - Blazor + Web API host
|
||||
cd EnvelopeGenerator.Server\EnvelopeGenerator.Server
|
||||
dotnet run
|
||||
```
|
||||
|
||||
**Critical:** `EnvelopeGenerator.Server` is the active runtime host for both UI and API controllers.
|
||||
|
||||
### Build
|
||||
```powershell
|
||||
dotnet build EnvelopeGenerator.sln
|
||||
```
|
||||
|
||||
## Project Boundaries
|
||||
|
||||
```
|
||||
EnvelopeGenerator.Domain/ # Entities (Envelope, Receiver, Document, etc.)
|
||||
EnvelopeGenerator.Application/ # MediatR CQRS (Commands, Queries, Handlers)
|
||||
EnvelopeGenerator.Infrastructure/ # EF Core, SQL executors, repositories
|
||||
EnvelopeGenerator.Server/
|
||||
EnvelopeGenerator.Server/ # Server-side Blazor + API controllers
|
||||
├─ Components/Pages/ # @rendermode InteractiveServer
|
||||
├─ Controllers/ # Active Web API endpoints
|
||||
EnvelopeGenerator.Server.Client/ # Client-side WASM components
|
||||
├─ Pages/ # @rendermode InteractiveWebAssembly
|
||||
├─ Services/ # HTTP API clients
|
||||
├─ Models/ # DTOs
|
||||
```
|
||||
|
||||
## Route Structure (Critical)
|
||||
|
||||
| Route | File Location | Render Mode | Purpose |
|
||||
|-------|--------------|-------------|---------|
|
||||
| `/` | `Server.Client/Pages/Index.razor` | WASM | Landing page |
|
||||
| `/sender/login` | `Server.Client/Pages/LoginSenderPage.razor` | WASM | Sender auth |
|
||||
| `/sender` | `Server/Components/Pages/EnvelopeSenderPage.razor` | **Server** | Sender dashboard |
|
||||
| `/sender/editor` | `Server/Components/Pages/EnvelopeSenderEditorPage.razor` | **Server** | Envelope editor + PDF viewer |
|
||||
| `/envelope/login/{key}` | `Server.Client/Pages/LoginReceiverPage.razor` | WASM | Receiver auth |
|
||||
| `/envelope/{key}` | `Server/Components/Pages/EnvelopeReceiverPage.razor` | **Server** | PDF viewer + signing |
|
||||
|
||||
**Rule:** PDF viewers MUST use `@rendermode InteractiveServer` (DevExpress backend requirement). Everything else uses WASM.
|
||||
|
||||
## Coordinate System (CRITICAL)
|
||||
|
||||
**Database stores INCHES** (GdPicture14 native). Origin: top-left, Y-axis down.
|
||||
|
||||
### Conversions
|
||||
```csharp
|
||||
// Database (INCHES) → PDF Points
|
||||
float points = inches * 72;
|
||||
|
||||
// Database (INCHES) → DevExpress DX
|
||||
float dx = inches * 100;
|
||||
|
||||
// PDF.js Pixels → Database (INCHES)
|
||||
float inches = (pixelX / canvasWidth) * pageWidthInches;
|
||||
```
|
||||
|
||||
**A4 Page:** 8.27" wide × 11.69" tall = 595pt × 842pt
|
||||
|
||||
**Signature Field Size:** 1.77" × 1.96" (FIXED, do not change)
|
||||
|
||||
**Evidence:** See `COPILOT_CONTEXT.md` lines 158-185, `EnvelopeGenerator.Form/frmFieldEditor.vb`
|
||||
|
||||
## API Architecture Quirks
|
||||
|
||||
### Monolithic Endpoint (Avoid for UI)
|
||||
`POST /api/EnvelopeReceiver` - Creates envelope+document+receivers+fields atomically.
|
||||
- **Use case:** External API consumers
|
||||
- **Not suitable for:** Step-by-step UI workflow (no draft support, no partial updates)
|
||||
|
||||
### Sender Workflow Endpoint
|
||||
```
|
||||
POST /api/Envelope # Create/update/save/send envelope workflow payload
|
||||
DELETE /api/Envelope/{id} # Delete with reason
|
||||
POST /api/Envelope/{id}/document # Upload PDF
|
||||
POST /api/Envelope/{id}/receivers # Add receiver
|
||||
POST /api/Envelope/{id}/signature-fields # Place signature field
|
||||
```
|
||||
|
||||
See `FORM_APPLICATION_CONTEXT.md` for detailed workflow requirements.
|
||||
|
||||
## Status Color Coding
|
||||
|
||||
Form app uses DevExpress `CustomDrawCell`. EnvelopeGenerator.Server needs CSS:
|
||||
|
||||
```css
|
||||
.envelope-row.status-partly-signed { background-color: #81C784; } /* GREEN_300 */
|
||||
.envelope-row.status-queued,
|
||||
.envelope-row.status-sent { background-color: #FFB74D; } /* ORANGE_300 */
|
||||
.envelope-row.status-completed { background-color: #81C784; }
|
||||
.envelope-row.status-deleted,
|
||||
.envelope-row.status-rejected { background-color: #E57373; } /* RED_300 */
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### YARP Proxy (`EnvelopeGenerator.Server/yarp.json`)
|
||||
Routes `/api/*`, `/swagger/*`, `/openapi/*`, `/scalar/*` → `https://localhost:8088`
|
||||
|
||||
### PDF.js Settings (`EnvelopeGenerator.Server/wwwroot/appsettings.json`)
|
||||
```json
|
||||
{
|
||||
"PdfViewerOptions": {
|
||||
"ThumbnailBaseScale": 0.75,
|
||||
"ThumbnailEnableHiDPI": true,
|
||||
"MainCanvasEnableHiDPI": true,
|
||||
"ZoomStepPercentage": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Server Host Config (`EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json`)
|
||||
- `ConnectionStrings:Default` - SQL Server DB
|
||||
- `AllowedOrigins` - CORS (includes `http://localhost:5131`, `http://localhost:7192`)
|
||||
- `Cache:SignatureCacheExpiration` - Signature persistence timeout
|
||||
- `PSPDFKitLicenseKey` - **DEPRECATED** (use PDF.js instead)
|
||||
|
||||
## Migration Status
|
||||
|
||||
### Complete ✅
|
||||
- Receiver login/authentication
|
||||
- PDF viewing with PDF.js (HiDPI, zoom, thumbnails)
|
||||
- Signature capture (draw/type/image)
|
||||
- Signature caching (Redis/SQL)
|
||||
- Sender login
|
||||
|
||||
### Missing (High Priority) ❌
|
||||
- Sender dashboard (`/sender`) - Empty stub
|
||||
- Envelope editor (`/sender/envelope/{id}`)
|
||||
- Signature field placement tool (PDF.js + draggable overlays)
|
||||
- Granular API endpoints (draft, receivers, fields)
|
||||
- Master-detail grids for receivers/history
|
||||
|
||||
## Common Mistakes (DO NOT REPEAT)
|
||||
|
||||
| Mistake | Why Wrong |
|
||||
|---------|-----------|
|
||||
| Using iText7 in receiver pages | GPL license issue. Use PDF.js overlays. |
|
||||
| Using PSPDFKit | Removed from architecture. Use PDF.js + DevExpress. |
|
||||
| `@rendermode InteractiveWebAssembly` on PDF viewers | DevExpress DxPdfViewer requires server-side rendering. |
|
||||
| Hardcoded quality in PDF.js | Use `appsettings.json` `PdfViewerOptions`. |
|
||||
| Coordinates in points/pixels for DB | Database uses INCHES. Convert before save. |
|
||||
| `BottomMarginBand` for signatures | Repeats on every page. Use `DetailBand`. |
|
||||
|
||||
## Testing
|
||||
|
||||
**No automated tests exist yet.**
|
||||
|
||||
Manual testing workflow:
|
||||
1. Start EnvelopeGenerator.Server (`dotnet run` in `EnvelopeGenerator.Server\EnvelopeGenerator.Server`)
|
||||
2. Navigate to `https://localhost:5131` (or check console output for port)
|
||||
3. Test sender login at `/sender/login`
|
||||
4. Test receiver flow at `/envelope/login/{envelopeKey}`
|
||||
|
||||
## Database
|
||||
|
||||
**SQL Server** (DD_ECM)
|
||||
- Connection string in `EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json`
|
||||
- EF Core migrations NOT used (manual SQL scripts)
|
||||
- Stored procedures: `PRSIG_*` prefix
|
||||
|
||||
**Key Tables:**
|
||||
- `TBSIG_ENVELOPE` - Envelope metadata
|
||||
- `TBSIG_ENVELOPE_RECEIVER` - Receiver assignments
|
||||
- `TBSIG_DOC_RECEIVER_ELEMENT` - Signature fields (X, Y in INCHES)
|
||||
- `TBSIG_RECEIVER` - Receiver registry
|
||||
- `TBSIG_DOCUMENT` - PDF binary data
|
||||
- `TBSIG_ENVELOPE_HISTORY` - Audit trail
|
||||
|
||||
## DevExpress
|
||||
|
||||
**License:** Commercial (v25.2.3)
|
||||
**Components Used:**
|
||||
- `DxGrid` - Master-detail grids
|
||||
- `DxPdfViewer` - Server-side PDF rendering
|
||||
- `DxPopup` - Modal dialogs
|
||||
- `DxToolbar` - Action bars
|
||||
- `DxFormLayout` - Forms
|
||||
|
||||
**Theme:** Blazing Berry (default)
|
||||
|
||||
## JavaScript Interop
|
||||
|
||||
**PDF Viewer:** `wwwroot/js/pdf-viewer.js`
|
||||
```javascript
|
||||
window.pdfViewer = {
|
||||
initialize(canvasId, pdfDataUrl, dotNetRef),
|
||||
renderPage(num),
|
||||
renderSignatureButtons(signatures, pageNum, dotNetRef),
|
||||
applySignature(signatureId, dataUrl, fullName, position, place),
|
||||
zoomIn(), zoomOut(), dispose()
|
||||
}
|
||||
```
|
||||
|
||||
**Signature Pad:** `wwwroot/js/receiver-signature.js`
|
||||
```javascript
|
||||
window.receiverSignature = {
|
||||
initializeDrawPad(canvasId, dotNetRef),
|
||||
getSignatureDataUrl(canvasId),
|
||||
clearPad(canvasId)
|
||||
}
|
||||
```
|
||||
|
||||
## Multi-Envelope Support
|
||||
|
||||
Receivers can login to **multiple envelopes simultaneously** via per-envelope cookies:
|
||||
```
|
||||
AuthTokenSignFLOWReceiver.{envelopeKey}
|
||||
```
|
||||
|
||||
Each envelope maintains independent authentication state.
|
||||
|
||||
## External Dependencies
|
||||
|
||||
**CDN:**
|
||||
- PDF.js 3.11.174: `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js`
|
||||
|
||||
**NuGet (Server.Client):**
|
||||
- `DevExpress.Blazor.*` 25.2.3
|
||||
- `SkiaSharp.*` 3.119.1 (WASM rendering)
|
||||
|
||||
**External Services:**
|
||||
- LDAP/AD authentication (optional)
|
||||
- GTX Messaging (SMS 2FA)
|
||||
- Email dispatcher (signFlow)
|
||||
|
||||
## Environment Variables
|
||||
|
||||
None required. All config in `appsettings.json`.
|
||||
|
||||
**Local dev ports:**
|
||||
- App host (UI + API): `https://localhost:5131` or `http://localhost:7192`
|
||||
@@ -1,351 +0,0 @@
|
||||
# EnvelopeGenerator — Current Workspace Context
|
||||
|
||||
## Purpose
|
||||
Digital document signing system for senders and receivers.
|
||||
|
||||
- Senders authenticate, view envelope lists, and manage envelope workflows.
|
||||
- Receivers authenticate per envelope, open PDFs, create signatures, and apply them in the viewer.
|
||||
- The active UI stack is `Blazor Auto` with server-side and WebAssembly render modes.
|
||||
- Primary UI/PDF libraries are `DevExpress` and `PDF.js`.
|
||||
|
||||
---
|
||||
|
||||
## Active Application Structure
|
||||
|
||||
### Main Host
|
||||
**Primary active application:** `EnvelopeGenerator.Server`
|
||||
|
||||
`EnvelopeGenerator.Server` is the current runtime host and contains:
|
||||
- Blazor server host
|
||||
- WebAssembly host integration
|
||||
- API controllers
|
||||
- authentication/authorization setup
|
||||
- Swagger/Scalar setup
|
||||
- YARP reverse proxy configuration
|
||||
- DevExpress server-side services
|
||||
- SQL Server distributed cache setup
|
||||
|
||||
### Client Project
|
||||
**Client UI project:** `EnvelopeGenerator.Server.Client`
|
||||
|
||||
This project contains:
|
||||
- WebAssembly-rendered pages
|
||||
- client-side services
|
||||
- client models and options
|
||||
- sender and receiver login flows
|
||||
|
||||
### Other Projects
|
||||
- `EnvelopeGenerator.Application` — MediatR/CQRS handlers and business logic
|
||||
- `EnvelopeGenerator.Domain` — domain models, constants, shared abstractions
|
||||
- `EnvelopeGenerator.Infrastructure` — EF Core and infrastructure services
|
||||
- `EnvelopeGenerator.PdfEditor` — PDF-related backend utilities
|
||||
- `EnvelopeGenerator.API` — deprecated project (no longer part of the active solution/runtime path)
|
||||
|
||||
### Legacy / Do Not Touch
|
||||
- `EnvelopeGenerator.Service`
|
||||
- `EnvelopeGenerator.Form`
|
||||
- `EnvelopeGenerator.BBTests`
|
||||
- `EnvelopeGenerator.CommonServices`
|
||||
|
||||
---
|
||||
|
||||
## Current Hosting Model
|
||||
|
||||
`EnvelopeGenerator.Server/Program.cs` currently configures:
|
||||
- `AddRazorComponents()` with both interactive server and interactive WebAssembly components
|
||||
- `AddControllers()` and `MapControllers()`
|
||||
- JWT authentication for sender and receiver flows
|
||||
- cookie authentication
|
||||
- authorization policies using `AuthScheme.Sender`, `AuthScheme.Receiver`, `AuthPolicy.Sender`, `AuthPolicy.Receiver`
|
||||
- `AddReverseProxy()` with `yarp.json`
|
||||
- Swagger / OpenAPI / Scalar
|
||||
- distributed SQL Server cache
|
||||
- DevExpress Blazor and DevExpress PDF Viewer server-side services
|
||||
- request localization middleware
|
||||
|
||||
This means the active app is a **merged UI + API host**.
|
||||
|
||||
---
|
||||
|
||||
## Reverse Proxy
|
||||
|
||||
**Config file:** `EnvelopeGenerator.Server/EnvelopeGenerator.Server/yarp.json`
|
||||
|
||||
Current YARP usage is focused on **AuthHub forwarding**, not a general `/api/* -> EnvelopeGenerator.API` proxy.
|
||||
|
||||
Configured routes forward:
|
||||
- `POST /api/auth` -> AuthHub `/api/auth/sign-flow`
|
||||
- `POST /api/Auth/envelope-receiver/{key}` -> AuthHub `/api/auth/envelope-receiver/{key}?cookie=true`
|
||||
|
||||
---
|
||||
|
||||
## Active Routes and Files
|
||||
|
||||
### WebAssembly Pages (`EnvelopeGenerator.Server.Client`)
|
||||
| Route | File | Render Mode | Purpose |
|
||||
|---|---|---|---|
|
||||
| `/` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/IndexPage.razor` | WebAssembly | Landing page |
|
||||
| `/sender/login` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginSenderPage.razor` | WebAssembly | Sender login |
|
||||
| `/sender` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor` | WebAssembly (`prerender: false`) | Sender dashboard |
|
||||
| `/envelope/login/{EnvelopeKey}` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/LoginReceiverPage.razor` | WebAssembly | Receiver login |
|
||||
|
||||
### Server Pages (`EnvelopeGenerator.Server`)
|
||||
| Route | File | Render Mode | Purpose |
|
||||
|---|---|---|---|
|
||||
| `/envelope/{EnvelopeKey}` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage.razor` | InteractiveServer | Main receiver PDF viewer and signing page |
|
||||
| `/envelope/DxPdfViewer` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_DxPdfViewer.razor` | InteractiveServer | DevExpress PDF Viewer test page |
|
||||
| `/envelope/{EnvelopeKey}/DxReportViewer` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_DxReportViewer.razor` | InteractiveServer | DevExpress report-based PDF rendering |
|
||||
| `/envelope/Embed` | `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_embed.razor` | InteractiveServer | Embedded browser PDF view test page |
|
||||
|
||||
---
|
||||
|
||||
## Current API Location
|
||||
|
||||
The active application exposes controllers from:
|
||||
`EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers`
|
||||
|
||||
Current controller set includes:
|
||||
- `AnnotationController`
|
||||
- `AuthController`
|
||||
- `CacheController`
|
||||
- `ConfigController`
|
||||
- `DocumentController`
|
||||
- `EmailTemplateController`
|
||||
- `EnvelopeController`
|
||||
- `EnvelopeReceiverController`
|
||||
- `EnvelopeTypeController`
|
||||
- `HistoryController`
|
||||
- `LocalizationController`
|
||||
- `ReadOnlyController`
|
||||
- `ReceiverController`
|
||||
- `SignatureController`
|
||||
- `TfaRegistrationController`
|
||||
|
||||
Do not assume API behavior lives in `EnvelopeGenerator.API`; the active merged host contains controller endpoints directly.
|
||||
|
||||
---
|
||||
|
||||
## Authentication Model
|
||||
|
||||
### Sender
|
||||
Client login page uses `EnvelopeGenerator.Server.Client/Services/AuthService.cs`.
|
||||
|
||||
Key sender endpoints:
|
||||
- `POST /api/auth?cookie=true` — login
|
||||
- `GET /api/auth/check` — current sender access check
|
||||
- `POST /api/auth/logout` — logout
|
||||
|
||||
### Receiver
|
||||
Receiver authentication is **per envelope**.
|
||||
|
||||
Key receiver endpoints used by client services:
|
||||
- `POST /api/Auth/envelope-receiver/{envelopeKey}` — submit access code
|
||||
- `GET /api/auth/check/envelope/{envelopeKey}` — check access
|
||||
- `POST /api/auth/logout/envelope/{envelopeKey}` — logout receiver for one envelope
|
||||
|
||||
Receiver cookie resolution in server auth uses an envelope-specific cookie name derived from:
|
||||
- `AuthTokenSignFLOWReceiver.{envelopeKey}` pattern
|
||||
|
||||
### Receiver Server-Side Authorization
|
||||
`EnvelopeReceiverPage.razor` does **not** rely on its own API access-check call for page authorization.
|
||||
|
||||
It uses:
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverAuthorizationService.cs`
|
||||
|
||||
Behavior:
|
||||
- tries the current `HttpContext.User`
|
||||
- if needed, reads the per-envelope receiver cookie directly
|
||||
- validates the JWT with the receiver auth scheme
|
||||
- verifies the token subject matches the route envelope key
|
||||
|
||||
---
|
||||
|
||||
## Receiver Page Data Loading
|
||||
|
||||
Main server-side page data service:
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverPageDataService.cs`
|
||||
|
||||
This service loads directly via MediatR and distributed cache:
|
||||
- document bytes
|
||||
- receiver envelope data
|
||||
- signature placeholders
|
||||
- cached signature data
|
||||
|
||||
For signature placeholders, the service:
|
||||
- reads document receiver elements
|
||||
- filters them for the authenticated receiver
|
||||
- converts coordinates to `UnitOfLength.Point` before UI use
|
||||
|
||||
---
|
||||
|
||||
## Receiver PDF Viewer
|
||||
|
||||
**Main file:** `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage.razor`
|
||||
|
||||
Current receiver viewer characteristics:
|
||||
- route: `/envelope/{EnvelopeKey}`
|
||||
- render mode: `InteractiveServer`
|
||||
- PDF rendering: `PDF.js`
|
||||
- toolbar: page navigation, zoom, thumbnail toggle, signature navigation, signature reset
|
||||
- signature popup: `DxPopup`
|
||||
- thumbnail sidebar: resizable and stored in `localStorage`
|
||||
|
||||
### JS Assets
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/js/pdf-viewer.js`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/js/receiver-signature.js`
|
||||
|
||||
### CSS
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/envelope-viewer.css`
|
||||
|
||||
### PDF.js CDN
|
||||
- `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js`
|
||||
- `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf_viewer.min.css`
|
||||
|
||||
---
|
||||
|
||||
## Signature Workflow
|
||||
|
||||
Receiver signatures are handled as a **viewer overlay workflow**.
|
||||
|
||||
### Current behavior
|
||||
1. Server-side authorization validates receiver access.
|
||||
2. The page loads document bytes, receiver data, signature placeholders, and cached signature state.
|
||||
3. If no cached signature exists, the signature popup opens automatically.
|
||||
4. Receiver creates signature using one of three tabs:
|
||||
- draw
|
||||
- text
|
||||
- image
|
||||
5. Required metadata:
|
||||
- full name
|
||||
- place
|
||||
6. Optional metadata:
|
||||
- position
|
||||
7. Clicking a signature placeholder applies the signature as a client-side overlay in the PDF viewer.
|
||||
|
||||
### Important note
|
||||
Although `itext` is referenced by the server project, the current receiver page signing flow is **not PDF stamping-based**. The active receiver UI uses client-side overlay behavior in the viewer.
|
||||
|
||||
### Signature DTO
|
||||
`EnvelopeGenerator.Server.Client/Models/SignatureCaptureDto.cs`
|
||||
|
||||
```csharp
|
||||
public sealed record SignatureCaptureDto {
|
||||
public required string DataUrl { get; init; }
|
||||
public required string FullName { get; init; }
|
||||
public string Position { get; init; } = "";
|
||||
public required string Place { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Signature Cache
|
||||
|
||||
### Active cache model
|
||||
The current receiver page cache flow is handled directly in the server project through:
|
||||
- `EnvelopeReceiverPageDataService`
|
||||
- `IDistributedCache`
|
||||
- SQL Server distributed cache configuration from `Program.cs`
|
||||
|
||||
### Cache key format
|
||||
Current server-side key prefix:
|
||||
- `envelope-generator.receiver-ui.signature:{receiverSignature}`
|
||||
|
||||
This is different from an envelope-key-only cache convention.
|
||||
|
||||
### Config
|
||||
`EnvelopeGenerator.Server/EnvelopeGenerator.Server/Options/CacheOptions.cs`
|
||||
- section name: `Cache`
|
||||
- option: `SignatureCacheExpiration`
|
||||
|
||||
### Related controller
|
||||
A cache API controller also exists in:
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/CacheController.cs`
|
||||
|
||||
---
|
||||
|
||||
## Sender Dashboard
|
||||
|
||||
**Main file:** `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor`
|
||||
|
||||
Current behavior:
|
||||
- checks sender access through `AuthService.CheckSenderAccessAsync()`
|
||||
- redirects to `/sender/login` when unauthorized
|
||||
- loads envelope list through client `EnvelopeService`
|
||||
- separates envelopes into active/completed tabs
|
||||
- uses `DevExpress DxGrid`
|
||||
|
||||
The sender page is active, but create/edit/delete actions are still marked with TODO behavior in the UI page.
|
||||
|
||||
---
|
||||
|
||||
## Localization
|
||||
|
||||
Current server host localization setup in `Program.cs`:
|
||||
- supported cultures: `de-DE`, `en-US`
|
||||
- request localization middleware is enabled
|
||||
- `QueryStringRequestCultureProvider` is added
|
||||
- cookie-based localization services are registered via `AddCookieBasedLocalizer()`
|
||||
|
||||
Do not assume the old ReceiverUI-only `localStorage` culture approach is the current source of truth for the active host.
|
||||
|
||||
---
|
||||
|
||||
## Coordinate System
|
||||
|
||||
### Source data
|
||||
Database signature coordinates are still based on:
|
||||
- **unit:** inches
|
||||
- **origin:** top-left
|
||||
- **axes:** X right, Y down
|
||||
|
||||
### Relevant conversions
|
||||
- inches -> PDF points: `x_pt = x_inches * 72`
|
||||
- inches -> DevExpress DX units: `x_dx = x_inches * 100`
|
||||
|
||||
### Current receiver page behavior
|
||||
The server page data service converts signature placeholders to **points** before sending them into the viewer workflow.
|
||||
|
||||
### Unit systems to keep in mind
|
||||
| System | Unit | Origin | Y-axis |
|
||||
|---|---|---|---|
|
||||
| Database | Inches | Top-left | Down |
|
||||
| PDF.js display | Pixels | Top-left | Down |
|
||||
| PDF points | Points | Depends on PDF model | Depends on consumer |
|
||||
| DevExpress DX | 1/100 inch style coordinates | Top-left-oriented usage in this app | Down-oriented usage |
|
||||
|
||||
---
|
||||
|
||||
## Key Services and Files
|
||||
|
||||
### Client services
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/AuthService.cs`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/EnvelopeService.cs`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/DocumentService.cs`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/SignatureCacheService.cs`
|
||||
|
||||
### Server services
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeAuthService.cs`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/IEnvelopeAuthService.cs`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverAuthorizationService.cs`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Services/EnvelopeReceiverPageDataService.cs`
|
||||
|
||||
### Server config and host files
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Program.cs`
|
||||
- `EnvelopeGenerator.Server/EnvelopeGenerator.Server/yarp.json`
|
||||
|
||||
---
|
||||
|
||||
## Working Rules for This Workspace
|
||||
|
||||
- Treat `EnvelopeGenerator.Server` as the active main application host.
|
||||
- Treat `EnvelopeGenerator.Server.Client` as the active client UI project.
|
||||
- Prefer current `Server` / `Server.Client` paths over old `WebUI` / `ReceiverUI` references.
|
||||
- Do not use `EnvelopeGenerator.Web` or `EnvelopeGenerator.ReceiverUI` as the primary implementation target unless explicitly asked.
|
||||
- Do not modify the legacy VB.NET projects unless explicitly requested.
|
||||
- For receiver PDF/signature work, prefer the current `PDF.js`-based flow in `EnvelopeReceiverPage.razor`.
|
||||
- For DevExpress PDF viewer issues, remember server-side services are registered in `EnvelopeGenerator.Server`.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-06-29
|
||||
@@ -1,36 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Commands;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand"></typeparam>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class CreateCommandHandler<TCommand, TEntity> : IRequestHandler<TCommand, TEntity>
|
||||
where TCommand : class, IRequest<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly IRepository<TEntity> Repository;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public CreateCommandHandler(IRepository<TEntity> repository)
|
||||
{
|
||||
Repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task<TEntity> Handle(TCommand request, CancellationToken cancel) => Repository.CreateAsync(request, cancel);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using MediatR;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Commands;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TUpdateDto"></typeparam>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public abstract record UpdateCommand<TUpdateDto, TEntity> : IRequest where TUpdateDto : class where TEntity : class
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public TUpdateDto Update { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract Expression<Func<TEntity, bool>> BuildQueryExpression();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand"></typeparam>
|
||||
/// <typeparam name="TUpdateDto"></typeparam>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class UpdateCommandHandler<TCommand, TUpdateDto, TEntity> : IRequestHandler<TCommand>
|
||||
where TUpdateDto : class
|
||||
where TEntity : class
|
||||
where TCommand : UpdateCommand<TUpdateDto, TEntity>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly IRepository<TEntity> Repository;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public UpdateCommandHandler(IRepository<TEntity> repository)
|
||||
{
|
||||
Repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task Handle(TCommand request, CancellationToken cancel)
|
||||
=> Repository.UpdateAsync(request.Update, request.BuildQueryExpression(), cancel);
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record AnnotationCreateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Not required for DevExpress")]
|
||||
public int ElementId { get; init; } = -1;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Not required for DevExpress")]
|
||||
public string Name { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Not required for DevExpress")]
|
||||
public string Value { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Not required for DevExpress")]
|
||||
public string Type { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal position of the signature field on the page.
|
||||
/// <br/><br/>
|
||||
/// <b>Unit:</b> INCHES (GdPicture14 native), origin at the <b>top-left</b> corner of the page, X increases to the right.
|
||||
/// <br/>
|
||||
/// <b>Conversion to DevExpress:</b> Multiply by 100 (DX uses 1/100 inch).
|
||||
/// Convert: <c>xDX = xInches * 100.0</c>
|
||||
/// <br/>
|
||||
/// <b>Conversion to PDF Points:</b> Multiply by 72 (PSPDFKit, iText7 use 1/72 inch).
|
||||
/// Convert: <c>xPt = xInches * 72.0</c>
|
||||
/// </summary>
|
||||
public double? X { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Vertical position of the signature field on the page.
|
||||
/// <br/><br/>
|
||||
/// <b>Unit:</b> INCHES (GdPicture14 native), origin at the <b>top-left</b> corner of the page, Y increases downward.
|
||||
/// <br/>
|
||||
/// <b>Conversion to DevExpress:</b> Multiply by 100 (DX uses 1/100 inch).
|
||||
/// Convert: <c>yDX = yInches * 100.0</c>
|
||||
/// <br/>
|
||||
/// <b>Conversion to PDF Points (top-left origin):</b> Multiply by 72.
|
||||
/// Convert: <c>yPt = yInches * 72.0</c>
|
||||
/// <br/>
|
||||
/// <b>Conversion to PDF Points (bottom-left origin - iText7):</b> Y-flip required.
|
||||
/// Convert: <c>yPt = (pageHeightInches - yInches - elemHeightInches) * 72.0</c>
|
||||
/// </summary>
|
||||
public double? Y { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Not required for DevExpress")]
|
||||
public double? Width { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Not required for DevExpress")]
|
||||
public double? Height { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Added to eliminate the need for SignatureDto in DevExpress
|
||||
/// </summary>
|
||||
public int? Page { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record AnnotationDto : AnnotationCreateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public long Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime AddedWhen { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime? ChangedWhen { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? ChangedWho { get; init; }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.Messaging;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class GtxMessagingResponse : Dictionary<string, object?> { }
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.Dynamic;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// Represents PSPDFKit annotation data.
|
||||
/// </summary>
|
||||
/// <param name="Instant">Instant annotation data.</param>
|
||||
/// <param name="Structured">Structured annotation data.</param>
|
||||
[Obsolete("The PSPDFKit library is deprecated.")]
|
||||
public record PsPdfKitAnnotation(ExpandoObject Instant, IEnumerable<AnnotationCreateDto> Structured);
|
||||
@@ -1,65 +0,0 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a captured signature with metadata created by the receiver in the signature popup.
|
||||
/// This model holds the signature image (as base64 data URL) along with signer information
|
||||
/// used for rendering applied signatures on the PDF canvas.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <b>Used in:</b> EnvelopeViewer.razor signature popup workflow
|
||||
/// <br/>
|
||||
/// <b>Creation:</b> User draws/types/uploads signature and fills required fields
|
||||
/// </remarks>
|
||||
public sealed record Signature
|
||||
{
|
||||
/// <summary>
|
||||
/// TBDD_DOCUMENT_RECEIVER_ELEMENT.ID - identifies the specific signature field on the PDF page.
|
||||
/// </summary>
|
||||
public required int Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Base64-encoded data URL of the signature image.
|
||||
/// <br/>
|
||||
/// <b>Format:</b> <c>data:image/png;base64,iVBORw0KG...</c>
|
||||
/// <br/>
|
||||
/// <b>Source:</b> Canvas.toDataURL() from signature pad (draw/text/image tabs)
|
||||
/// <br/>
|
||||
/// <b>Usage:</b> Set as <c>img.src</c> in applied signature overlay
|
||||
/// </summary>
|
||||
public required string DataUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Full name of the signer (first and last name).
|
||||
/// <br/>
|
||||
/// <b>Required:</b> Yes (validated in popup)
|
||||
/// <br/>
|
||||
/// <b>Example:</b> "Max Mustermann"
|
||||
/// </summary>
|
||||
public required string FullName { get; init; }
|
||||
|
||||
private readonly string? _position = null;
|
||||
|
||||
/// <summary>
|
||||
/// Job title or position of the signer.
|
||||
/// <br/>
|
||||
/// <b>Required:</b> No (optional field)
|
||||
/// <br/>
|
||||
/// <b>Example:</b> "Geschäftsführer" or empty string
|
||||
/// </summary>
|
||||
public string? Position
|
||||
{
|
||||
get => _position;
|
||||
init => _position = string.IsNullOrWhiteSpace(value) ? value : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Location/place where the signature was created.
|
||||
/// <br/>
|
||||
/// <b>Required:</b> Yes (validated in popup)
|
||||
/// <br/>
|
||||
/// <b>Display:</b> Shown with current date in German format (dd.MM.yyyy)
|
||||
/// <br/>
|
||||
/// <b>Example:</b> "Berlin" ? rendered as "Berlin, 26.01.2025"
|
||||
/// </summary>
|
||||
public required string Place { get; init; }
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a user's UI preferences stored in the distributed cache (dbo.TBDD_CACHE).
|
||||
/// </summary>
|
||||
public sealed record UserPreferencesDto
|
||||
{
|
||||
/// <summary>
|
||||
/// The active DevExpress theme name.
|
||||
/// Allowed values: "blazing-berry", "fluent", "purple"
|
||||
/// </summary>
|
||||
public string ThemeName { get; set; } = "blazing-berry";
|
||||
|
||||
/// <summary>
|
||||
/// Whether dark mode is active.
|
||||
/// Default: false (light mode).
|
||||
/// </summary>
|
||||
public bool IsDarkMode { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Persisted DxGrid layout states, keyed by a stable grid identifier.
|
||||
/// Example keys: "sender.active-envelopes", "sender.completed-envelopes"
|
||||
/// Values are opaque JSON strings produced by DxGrid.SaveLayoutAsync().
|
||||
/// </summary>
|
||||
public Dictionary<string, string> GridLayouts { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The authenticated user's display name ("{GivenName} {Surname}").
|
||||
/// Populated by the server on GET responses from JWT claims.
|
||||
/// NOT persisted in cache — injected at read time by UserPreferencesController.
|
||||
/// Ignored on PUT requests.
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static UserPreferencesDto Default { get; } = new UserPreferencesDto();
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
namespace EnvelopeGenerator.Application.Common;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum EnvelopeFlag
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
EnvelopeOrReceiverNonexists,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
NonDecodableEnvelopeReceiverId,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
WrongEnvelopeReceiverId,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
AccessCodeNull
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Domain.Interfaces.Auditing;
|
||||
using System;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for applying auditing timestamps during AutoMapper mappings.
|
||||
/// </summary>
|
||||
public static class AutoMapperAuditingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps <see cref="IHasAddedWhen.AddedWhen"/> to the current UTC time.
|
||||
/// </summary>
|
||||
public static IMappingExpression<TSource, TDestination> MapAddedWhen<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
|
||||
where TDestination : IHasAddedWhen
|
||||
=> expression.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.Now));
|
||||
|
||||
/// <summary>
|
||||
/// Maps <see cref="IHasChangedWhen.ChangedWhen"/> to the current UTC time.
|
||||
/// </summary>
|
||||
public static IMappingExpression<TSource, TDestination> MapChangedWhen<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
|
||||
where TDestination : IHasChangedWhen
|
||||
=> expression.ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(_ => DateTime.Now));
|
||||
|
||||
/// <summary>
|
||||
/// Converts a base64 data URL string to a byte array.
|
||||
/// Handles data URLs in the format: "data:image/png;base64,iVBORw0KG..."
|
||||
/// </summary>
|
||||
/// <param name="dataUrl">The base64 data URL string from Canvas.toDataURL()</param>
|
||||
/// <returns>The decoded byte array, or null if the input is null or empty</returns>
|
||||
public static byte[]? MapDataUrlToRequiredBytes(this string dataUrl)
|
||||
{
|
||||
// Remove data URL prefix (e.g., "data:image/png;base64,")
|
||||
var base64Index = dataUrl.IndexOf(',', StringComparison.Ordinal);
|
||||
if (base64Index == -1)
|
||||
throw new ArgumentException("Invalid data URL format. Unable to extract base64 data.", nameof(dataUrl));
|
||||
|
||||
var base64Data = dataUrl[(base64Index + 1)..];
|
||||
return Convert.FromBase64String(base64Data);
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class DecodingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates whether a given string is a correctly formatted Base-64 encoded string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method checks the string for proper Base-64 formatting, which includes validating
|
||||
/// the length of the string (must be divisible by 4). It also checks each character to ensure
|
||||
/// it belongs to the Base-64 character set (A-Z, a-z, 0-9, '+', '/', and '=' for padding).
|
||||
/// The method ensures that padding characters ('=') only appear at the end of the string and
|
||||
/// are in a valid configuration (either one '=' at the end if the string's length % 4 is 3,
|
||||
/// or two '==' if the length % 4 is 2).
|
||||
/// </remarks>
|
||||
/// <param name="input">The Base-64 encoded string to validate.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the string is a valid Base-64 encoded string; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// string testString = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnk=";
|
||||
/// bool isValid = IsValidBase64String(testString);
|
||||
/// Console.WriteLine(isValid); // Output: true
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static bool IsBase64String(this string input)
|
||||
{
|
||||
// Check if the string is null or empty
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replace valid base-64 padding
|
||||
input = input.Trim();
|
||||
int mod4 = input.Length % 4;
|
||||
if (mod4 > 0)
|
||||
{
|
||||
// Base-64 string lengths should be divisible by 4
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each character to ensure it is valid base-64
|
||||
foreach (char c in input)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(c) && c != '+' && c != '/' && c != '=')
|
||||
{
|
||||
// Invalid character detected
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure no invalid padding scenarios exist
|
||||
if (input.EndsWith("==") && input.Length % 4 == 0 ||
|
||||
input.EndsWith("=") && input.Length % 4 == 3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return input.IndexOf('=') == -1; // No padding allowed except at the end
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="encodedKey"></param>
|
||||
/// <param name="decodedKeys"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryDecode(this string encodedKey, out string[] decodedKeys)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] bytes = Convert.FromBase64String(encodedKey);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
decodedKeys = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
return true;
|
||||
}
|
||||
catch(ArgumentNullException) { }
|
||||
catch (FormatException) { }
|
||||
catch(ArgumentException) { }
|
||||
|
||||
decodedKeys = Array.Empty<string>();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="decodedKeys"></param>
|
||||
/// <returns></returns>
|
||||
public static EncodeType GetEncodeType(this string[] decodedKeys) => decodedKeys.Length switch
|
||||
{
|
||||
2 => EncodeType.EnvelopeReceiver,
|
||||
3 => long.TryParse(decodedKeys[1], out var _) ? EncodeType.EnvelopeReceiverReadOnly : EncodeType.Undefined,
|
||||
_ => EncodeType.Undefined,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="decodedKeys"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public static (string? EnvelopeUuid, string? ReceiverSignature) ParseEnvelopeReceiverId(this string[] decodedKeys)
|
||||
=> decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiver
|
||||
? (EnvelopeUuid: decodedKeys[0], ReceiverSignature: decodedKeys[1])
|
||||
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver.");
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="decodedKeys"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public static long ParseReadOnlyId(this string[] decodedKeys)
|
||||
=> decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly
|
||||
? long.Parse(decodedKeys[1])
|
||||
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. ");
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string containing the envelope UUID and receiver signature.</param>
|
||||
/// <returns>A tuple containing the envelope UUID and receiver signature.</returns>
|
||||
public static (string? EnvelopeUuid, string? ReceiverSignature) DecodeEnvelopeReceiverId(this string envelopeReceiverId)
|
||||
{
|
||||
if (!envelopeReceiverId.IsBase64String())
|
||||
{
|
||||
return (null, null);
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverId);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 1)
|
||||
return (EnvelopeUuid: parts[0], ReceiverSignature: parts[1]);
|
||||
else
|
||||
return (string.Empty, string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverReadOnlyId"></param>
|
||||
/// <returns></returns>
|
||||
public static long? DecodeEnvelopeReceiverReadOnlyId(this string envelopeReceiverReadOnlyId)
|
||||
{
|
||||
if (!envelopeReceiverReadOnlyId.IsBase64String())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverReadOnlyId);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 2)
|
||||
return long.TryParse(parts[1], out long readOnlyId) ? readOnlyId : null;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the envelope UUID from the decoded envelope receiver ID.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
|
||||
/// <returns>The envelope UUID.</returns>
|
||||
public static string? GetEnvelopeUuid(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().EnvelopeUuid;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the receiver signature from the decoded envelope receiver ID.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
|
||||
/// <returns>The receiver signature.</returns>
|
||||
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for decoding and extracting information from an envelope receiver ID.
|
||||
/// </summary>
|
||||
public static class EncodingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="readOnlyId"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToEnvelopeKey(this long readOnlyId)
|
||||
{
|
||||
//The random number is used as a salt to increase security but it is not saved in the database.
|
||||
string combinedString = $"{Random.Shared.Next()}::{readOnlyId}::{Random.Shared.Next()}";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
|
||||
string base64String = Convert.ToBase64String(bytes);
|
||||
|
||||
return base64String;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToEnvelopeKey(this (string envelopeUuid, string receiverSignature) input)
|
||||
{
|
||||
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
|
||||
string base64String = Convert.ToBase64String(bytes);
|
||||
|
||||
return base64String;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class JsonExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToJson(this object obj, JsonSerializerOptions? options = null)
|
||||
=> JsonSerializer.Serialize(obj, options);
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
using DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Query;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Domain.Interfaces;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class QueryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="notnull"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BadRequestException"></exception>
|
||||
public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> root, EnvelopeQueryBase query, bool notnull = true)
|
||||
where TEntity : IHasEnvelope
|
||||
{
|
||||
if (query.Id is not null)
|
||||
root = root.Where(e => e.Envelope!.Id == query.Id);
|
||||
else if (query.Uuid is not null)
|
||||
root = root.Where(e => e.Envelope!.Uuid == query.Uuid);
|
||||
else if (notnull)
|
||||
throw new BadRequestException(
|
||||
"Either Envelope Id or Envelope Uuid must be provided in the query."
|
||||
);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="notnull"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BadRequestException"></exception>
|
||||
public static IQueryable<Envelope> Where(this IQueryable<Envelope> root, EnvelopeQueryBase query, bool notnull = true)
|
||||
{
|
||||
if (query.Id is not null)
|
||||
root = root.Where(e => e.Id == query.Id);
|
||||
else if (query.Uuid is not null)
|
||||
root = root.Where(e => e.Uuid == query.Uuid);
|
||||
else if (notnull)
|
||||
throw new BadRequestException(
|
||||
"Either Envelope Id or Envelope Uuid must be provided in the query."
|
||||
);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="notnull"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BadRequestException"></exception>
|
||||
public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> root, ReceiverQueryBase query, bool notnull = true)
|
||||
where TEntity : IHasReceiver
|
||||
{
|
||||
if (query.Id is not null)
|
||||
root = root.Where(e => e.Receiver!.Id == query.Id);
|
||||
else if (query.EmailAddress is not null)
|
||||
root = root.Where(e => e.Receiver!.EmailAddress == query.EmailAddress);
|
||||
else if (query.Signature is not null)
|
||||
root = root.Where(e => e.Receiver!.Signature == query.Signature);
|
||||
else if (notnull)
|
||||
throw new BadRequestException(
|
||||
"Receiver must have at least one identifier (Id, EmailAddress, or Signature)."
|
||||
);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="notnull"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BadRequestException"></exception>
|
||||
public static IQueryable<Receiver> Where(this IQueryable<Receiver> root, ReceiverQueryBase query, bool notnull = true)
|
||||
{
|
||||
if (query.Id is not null)
|
||||
root = root.Where(e => e.Id == query.Id);
|
||||
else if (query.EmailAddress is not null)
|
||||
root = root.Where(e => e.EmailAddress == query.EmailAddress);
|
||||
else if (query.Signature is not null)
|
||||
root = root.Where(e => e.Signature == query.Signature);
|
||||
else if (notnull)
|
||||
throw new BadRequestException(
|
||||
"Receiver must have at least one identifier (Id, EmailAddress, or Signature)."
|
||||
);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TEnvelopeQuery"></typeparam>
|
||||
/// <typeparam name="TReceiverQuery"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="notnull"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<TEntity> Where<TEntity, TEnvelopeQuery, TReceiverQuery>(this IQueryable<TEntity> root, EnvelopeReceiverQueryBase<TEnvelopeQuery, TReceiverQuery> query, bool notnull = true)
|
||||
where TEntity : IHasEnvelope, IHasReceiver
|
||||
where TEnvelopeQuery : EnvelopeQueryBase, new()
|
||||
where TReceiverQuery : ReceiverQueryBase, new()
|
||||
=> root.Where(query.Envelope, notnull).Where(query.Receiver, notnull);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using OtpNet;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class StringExtension
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="totp"></param>
|
||||
/// <param name="secret"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidTotp(this string totp, string secret)
|
||||
{
|
||||
var secret_bytes = Base32Encoding.ToBytes(secret);
|
||||
var secret_totp = new Totp(secret_bytes);
|
||||
return secret_totp.VerifyTotp(totp, out _, VerificationWindow.RfcSpecifiedNetworkDelay);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="seperator"></param>
|
||||
/// <param name="values"></param>
|
||||
/// <returns></returns>
|
||||
public static string Join(this IEnumerable<string> values, string seperator) => string.Join(seperator, values);
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
using DigitalData.Core.Exceptions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for tasks
|
||||
/// </summary>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static class TaskExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Awaits the specified task and ensures that the result is not <c>null</c>.
|
||||
/// If the result is <c>null</c>, the exception created by factory-method is thrown.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the result.</typeparam>
|
||||
/// <typeparam name="TException">The type of the exception.</typeparam>
|
||||
/// <param name="task">The task to await.</param>
|
||||
/// <param name="factory">Exception provider</param>
|
||||
/// <returns>The awaited result if not <c>null</c>.</returns>
|
||||
/// <exception>Thrown if the result is <c>null</c>.</exception>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static async Task<T> ThrowIfNull<T, TException>(this Task<T?> task, Func<TException> factory) where TException : Exception
|
||||
{
|
||||
var result = await task;
|
||||
return result ?? throw factory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Awaits the specified task and ensures that the result is not <c>empty</c>.
|
||||
/// If the result contains no elements, the exception created by factory-method is thrown.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The element type of the collection.</typeparam>
|
||||
/// <typeparam name="TException">The type of the exception.</typeparam>
|
||||
/// <param name="task">The task to await.</param>
|
||||
/// <param name="factory">Exception provider</param>
|
||||
/// <returns>The awaited collection if it is not <c>null</c> or empty.</returns>
|
||||
/// <exception cref="NotFoundException">Thrown if the result is <c>null</c> or empty.</exception>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static async Task<IEnumerable<T>> ThrowIfEmpty<T, TException>(this Task<IEnumerable<T>> task, Func<TException> factory) where TException : Exception
|
||||
{
|
||||
var result = await task;
|
||||
return result?.Any() ?? false ? result : throw factory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="I"></typeparam>
|
||||
/// <param name="task"></param>
|
||||
/// <param name="act"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static async Task<I> Then<T, I>(this Task<T> task, Func<T, I> act)
|
||||
{
|
||||
var res = await task;
|
||||
return act(res);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static Task<T?> FirstOrDefaultAsync<T>(this Task<IEnumerable<T>> task) => task.Then(t => t.FirstOrDefault());
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TException"></typeparam>
|
||||
/// <param name="task"></param>
|
||||
/// <param name="factory"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<T> FirstAsync<T, TException>(this Task<IEnumerable<T>> task, Func<TException> factory)
|
||||
where TException : Exception
|
||||
=> task.Then(t => t.FirstOrDefault() ?? throw factory());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static NotFoundException NotFound() => new();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static BadRequestException BadRequest() => new();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Implement Mediator behaviors in the Osolete .NET project.")]
|
||||
public static ForbiddenException Forbidden() => new();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using Ganss.Xss;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class XSSExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="encoder"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TryEncode(this string? value, UrlEncoder encoder) => value is null ? value : encoder.Encode(value);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="encoder"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TryEncode(this LocalizedString? value, UrlEncoder encoder) => value is null ? null : encoder.Encode(value);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="html"></param>
|
||||
/// <param name="sanitizer"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TrySanitize(this string? html, HtmlSanitizer sanitizer) => html is null ? html : sanitizer.Sanitize(html);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="html"></param>
|
||||
/// <param name="sanitizer"></param>
|
||||
/// <returns></returns>
|
||||
public static string? TrySanitize(this LocalizedString? html, HtmlSanitizer sanitizer) => html is null ? null : sanitizer.Sanitize(html);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use MediatR")]
|
||||
public interface IEnvelopeDocumentService : IBasicCRUDService<DocumentDto, Document, int>
|
||||
{
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Manages per-user UI preferences (theme, dark mode, grid layouts).
|
||||
/// Preferences are stored in the distributed cache (dbo.TBDD_CACHE) as JSON.
|
||||
/// Cache key schema: "signflow.user-preferences:{username}"
|
||||
/// </summary>
|
||||
public interface IUserPreferencesService
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves preferences for the given user.
|
||||
/// Always returns a valid object — never throws, never returns null.
|
||||
/// Returns defaults if no entry exists in cache.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task<UserPreferencesDto> GetOrCreateAsync(string id, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Persists the given preferences for the user in the distributed cache.
|
||||
/// Failures are non-fatal and silently ignored.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="preferences">The preferences to persist.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task SaveAsync(string id, UserPreferencesDto preferences, CancellationToken ct = default);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.Common.Dto.History;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Messaging;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the AutoMapper profile configuration for mapping between
|
||||
/// domain entities and data transfer objects (DTOs) used within the EnvelopeGenerator application.
|
||||
/// </summary>
|
||||
public class MappingProfile : Profile
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MappingProfile"/> class.
|
||||
/// Configures the mappings between entities and DTOs used throughout the application.
|
||||
/// </summary>
|
||||
public MappingProfile()
|
||||
{
|
||||
// Entity to DTO mappings
|
||||
CreateMap<Config, ConfigDto>();
|
||||
CreateMap<DocReceiverElement, DocReceiverElementDto>();
|
||||
CreateMap<DocumentStatus, DocumentStatusDto>();
|
||||
CreateMap<EmailTemplate, EmailTemplateDto>();
|
||||
CreateMap<Envelope, EnvelopeDto>()
|
||||
.ForMember(dest => dest.EnvelopeTypeTitle,
|
||||
opt => opt.MapFrom(src => src.Type != null ? src.Type.Title : null));
|
||||
CreateMap<Document, DocumentDto>();
|
||||
CreateMap<History, HistoryDto>().ForMember(dest => dest.ActionDate, opt => opt.MapFrom(src => src.ChangedWhen));
|
||||
CreateMap<History, HistoryCreateDto>().ForMember(dest => dest.ActionDate, opt => opt.MapFrom(src => src.ChangedWhen));
|
||||
CreateMap<EnvelopeReceiver, EnvelopeReceiverDto>();
|
||||
CreateMap<EnvelopeReceiver, EnvelopeReceiverSecretDto>();
|
||||
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
||||
CreateMap<Receiver, ReceiverDto>();
|
||||
CreateMap<EnvelopeReceiverReadOnly, EnvelopeReceiverReadOnlyDto>();
|
||||
CreateMap<ElementAnnotation, AnnotationDto>();
|
||||
|
||||
// DTO to Entity mappings
|
||||
CreateMap<ConfigDto, Config>();
|
||||
CreateMap<DocReceiverElementDto, DocReceiverElement>();
|
||||
CreateMap<Signature, DocReceiverElement>()
|
||||
.ForMember(dest => dest.Ink, opt => opt.MapFrom(src => src.DataUrl.MapDataUrlToRequiredBytes()))
|
||||
.MapChangedWhen();
|
||||
CreateMap<DocumentStatusDto, DocumentStatus>();
|
||||
CreateMap<EmailTemplateDto, EmailTemplate>();
|
||||
CreateMap<EnvelopeDto, Envelope>();
|
||||
CreateMap<DocumentDto, Document>();
|
||||
CreateMap<HistoryDto, History>().ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(src => src.ActionDate));
|
||||
CreateMap<HistoryCreateDto, History>().ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(src => src.ActionDate));
|
||||
CreateMap<EnvelopeReceiverDto, EnvelopeReceiver>();
|
||||
CreateMap<EnvelopeTypeDto, EnvelopeType>();
|
||||
CreateMap<ReceiverDto, Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
|
||||
CreateMap<EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnly>();
|
||||
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly>();
|
||||
CreateMap<AnnotationCreateDto, ElementAnnotation>()
|
||||
.MapAddedWhen();
|
||||
|
||||
// Messaging mappings
|
||||
// for GTX messaging
|
||||
CreateMap<GtxMessagingResponse, SmsResponse>()
|
||||
.ConstructUsing(gtxRes => gtxRes.Ok()
|
||||
? new SmsResponse() { Ok = true }
|
||||
: new SmsResponse() { Ok = false, Errors = gtxRes });
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned;
|
||||
|
||||
/// <summary>
|
||||
/// Notification raised when a document is signed by a receiver.
|
||||
/// </summary>
|
||||
[Obsolete("This notification is deprecated. Use Signature.Commands.SignCommand instead.")]
|
||||
public record DocSignedNotification : INotification, ISendMailNotification
|
||||
{
|
||||
/// <summary>
|
||||
/// The envelope receiver information.
|
||||
/// </summary>
|
||||
public required EnvelopeReceiverDto EnvelopeReceiver { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The PSPDFKit annotation data.
|
||||
/// </summary>
|
||||
[Obsolete("The PSPDFKit library is deprecated.")]
|
||||
public PsPdfKitAnnotation? PsPdfKitAnnotation { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the email template type.
|
||||
/// </summary>
|
||||
public EmailTemplateType TemplateType => EmailTemplateType.DocumentSigned;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the email address of the receiver.
|
||||
/// </summary>
|
||||
public string EmailAddress => EnvelopeReceiver.Receiver?.EmailAddress
|
||||
?? throw new InvalidOperationException($"Receiver is null." +
|
||||
$"DocSignedNotification:\n{this.ToJson(Format.Json.ForDiagnostics)}");
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("The PSPDFKit library is deprecated.")]
|
||||
public class AnnotationHandler : INotificationHandler<DocSignedNotification>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private readonly IRepository<ElementAnnotation> _repo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public AnnotationHandler(IRepository<ElementAnnotation> repository)
|
||||
{
|
||||
_repo = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public async Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
||||
{
|
||||
if (notification.PsPdfKitAnnotation is PsPdfKitAnnotation annot)
|
||||
await _repo.CreateAsync(annot.Structured, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using EnvelopeGenerator.Application.DocStatus.Commands;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("This notification is deprecated. Use Signature.Commands.SignCommand instead.")]
|
||||
public class DocStatusHandler : INotificationHandler<DocSignedNotification>
|
||||
{
|
||||
private const string BlankAnnotationJson = "{}";
|
||||
|
||||
private readonly ISender _sender;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
public DocStatusHandler(ISender sender)
|
||||
{
|
||||
_sender = sender;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("This notification is deprecated. Use Signature.Commands.SignCommand instead.")]
|
||||
public Task Handle(DocSignedNotification notification, CancellationToken cancel) => _sender.Send(new CreateDocStatusCommand()
|
||||
{
|
||||
EnvelopeId = notification.EnvelopeReceiver.EnvelopeId,
|
||||
ReceiverId = notification.EnvelopeReceiver.ReceiverId,
|
||||
Value = notification.PsPdfKitAnnotation is PsPdfKitAnnotation annot
|
||||
? JsonSerializer.Serialize(annot.Instant, Format.Json.ForAnnotations)
|
||||
: BlankAnnotationJson
|
||||
}, cancel);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Histories.Commands;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class HistoryHandler : INotificationHandler<DocSignedNotification>
|
||||
{
|
||||
private readonly ISender _sender;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
public HistoryHandler(ISender sender)
|
||||
{
|
||||
_sender = sender;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public async Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
||||
{
|
||||
if (notification.EnvelopeReceiver.Receiver is null)
|
||||
throw new InvalidOperationException($"Receiver information is missing in the notification. DocSignedNotification:\n {notification.ToJson(Format.Json.ForDiagnostics)}");
|
||||
|
||||
await _sender.Send(new CreateHistoryCommand()
|
||||
{
|
||||
EnvelopeId = notification.EnvelopeReceiver.EnvelopeId,
|
||||
UserReference = notification.EnvelopeReceiver.Receiver.EmailAddress,
|
||||
Status = EnvelopeStatus.DocumentSigned,
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
|
||||
using EnvelopeGenerator.Application.Common.Configurations;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.Extensions.Options;
|
||||
using EnvelopeGenerator.Domain.Interfaces;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class SendSignedMailHandler : SendMailHandler<DocSignedNotification>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="tempRepo"></param>
|
||||
/// <param name="emailOutRepo"></param>
|
||||
/// <param name="mailParamsOptions"></param>
|
||||
/// <param name="dispatcherParamsOptions"></param>
|
||||
public SendSignedMailHandler(IRepository<EmailTemplate> tempRepo, IRepository<EmailOut> emailOutRepo, IOptions<MailParams> mailParamsOptions, IOptions<DispatcherParams> dispatcherParamsOptions) : base(tempRepo, emailOutRepo, mailParamsOptions, dispatcherParamsOptions)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="emailOut"></param>
|
||||
protected override void ConfigureEmailOut(DocSignedNotification notification, EmailOut emailOut)
|
||||
{
|
||||
emailOut.ReferenceString = notification.EmailAddress;
|
||||
emailOut.ReferenceId = notification.EnvelopeReceiver.ReceiverId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <returns></returns>
|
||||
protected override Dictionary<string, string> CreatePlaceHolders(DocSignedNotification notification)
|
||||
{
|
||||
var placeHolders = new Dictionary<string, string>()
|
||||
{
|
||||
{ "[NAME_RECEIVER]", notification.EnvelopeReceiver.Name ?? string.Empty },
|
||||
{ "[DOCUMENT_TITLE]", notification.EnvelopeReceiver.Envelope?.Title ?? string.Empty },
|
||||
};
|
||||
|
||||
if (notification.EnvelopeReceiver.Envelope.IsReadAndConfirm())
|
||||
{
|
||||
placeHolders["[SIGNATURE_TYPE]"] = "Lesen und bestätigen";
|
||||
placeHolders["[DOCUMENT_PROCESS]"] = string.Empty;
|
||||
placeHolders["[FINAL_STATUS]"] = "Lesebestätigung";
|
||||
placeHolders["[FINAL_ACTION]"] = "Empfänger bestätigt";
|
||||
placeHolders["[REJECTED_BY_OTHERS]"] = "anderen Empfänger abgelehnt!";
|
||||
placeHolders["[RECEIVER_ACTION]"] = "bestätigt";
|
||||
}
|
||||
else
|
||||
{
|
||||
placeHolders["[SIGNATURE_TYPE]"] = "Signieren";
|
||||
placeHolders["[DOCUMENT_PROCESS]"] = " und elektronisch unterschreiben";
|
||||
placeHolders["[FINAL_STATUS]"] = "Signatur";
|
||||
placeHolders["[FINAL_ACTION]"] = "Vertragspartner unterzeichnet";
|
||||
placeHolders["[REJECTED_BY_OTHERS]"] = "anderen Vertragspartner abgelehnt! Ihre notwendige Unterzeichnung wurde verworfen.";
|
||||
placeHolders["[RECEIVER_ACTION]"] = "unterschrieben";
|
||||
}
|
||||
|
||||
return placeHolders;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.EnvelopeDeleted;
|
||||
|
||||
public record EnvelopeDeletedNotification : INotification, ISendMailNotification
|
||||
{
|
||||
public required Envelope Envelope { get; init; }
|
||||
|
||||
public required EnvelopeReceiver EnvelopeReceiver { get; init; }
|
||||
|
||||
public required string Reason { get; init; }
|
||||
|
||||
public required string SenderReference { get; init; }
|
||||
|
||||
public EmailTemplateType TemplateType => EmailTemplateType.DocumentDeleted;
|
||||
|
||||
public string EmailAddress => EnvelopeReceiver.Receiver?.EmailAddress
|
||||
?? throw new InvalidOperationException("Receiver email is missing for EnvelopeDeletedNotification.");
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
|
||||
using EnvelopeGenerator.Application.Common.Configurations;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.EnvelopeDeleted.Handlers;
|
||||
|
||||
public class SendDeletedMailHandler : SendMailHandler<EnvelopeDeletedNotification>
|
||||
{
|
||||
public SendDeletedMailHandler(
|
||||
IRepository<EmailTemplate> tempRepo,
|
||||
IRepository<EmailOut> emailOutRepo,
|
||||
IOptions<MailParams> mailParamsOptions,
|
||||
IOptions<DispatcherParams> dispatcherParamsOptions)
|
||||
: base(tempRepo, emailOutRepo, mailParamsOptions, dispatcherParamsOptions)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ConfigureEmailOut(EnvelopeDeletedNotification notification, EmailOut emailOut)
|
||||
{
|
||||
emailOut.ReferenceString = notification.EmailAddress;
|
||||
emailOut.ReferenceId = notification.EnvelopeReceiver.ReceiverId;
|
||||
emailOut.WfId = (int)EnvelopeStatus.MessageDeletionSent;
|
||||
}
|
||||
|
||||
protected override Dictionary<string, string> CreatePlaceHolders(EnvelopeDeletedNotification notification)
|
||||
{
|
||||
var senderName = notification.Envelope.User?.Email;
|
||||
if (string.IsNullOrWhiteSpace(senderName))
|
||||
senderName = notification.SenderReference;
|
||||
|
||||
return new Dictionary<string, string>
|
||||
{
|
||||
["[NAME_RECEIVER]"] = notification.EnvelopeReceiver.Name ?? string.Empty,
|
||||
["[NAME_SENDER]"] = senderName ?? string.Empty,
|
||||
["[DOCUMENT_TITLE]"] = notification.Envelope.Title ?? string.Empty,
|
||||
["[REASON]"] = notification.Reason
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class RemoveAnnotationHandler : INotificationHandler<RemoveSignatureNotification>
|
||||
{
|
||||
private readonly IRepository<ElementAnnotation> _repo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public RemoveAnnotationHandler(IRepository<ElementAnnotation> repository)
|
||||
{
|
||||
_repo = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
|
||||
{
|
||||
notification.ThrowIfHasNoFilter();
|
||||
return _repo.DeleteAsync(annots =>
|
||||
{
|
||||
// envelope ID filter
|
||||
if (notification.EnvelopeId is int envelopeId)
|
||||
annots = annots.Where(annot => annot.Element!.Document.EnvelopeId == envelopeId);
|
||||
|
||||
// envelope UUID filter
|
||||
if (notification.EnvelopeUuid is string envelopeUuid)
|
||||
annots = annots.Where(annot => annot.Element!.Document.Envelope!.Uuid == envelopeUuid);
|
||||
|
||||
// receiver ID
|
||||
if (notification.ReceiverId is int receiverId)
|
||||
annots = annots.Where(annot => annot.Element!.ReceiverId == receiverId);
|
||||
|
||||
// receiver signature
|
||||
if (notification.ReceiverSignature is string receiverSignature)
|
||||
annots = annots.Where(annot => annot.Element!.Receiver!.Signature == receiverSignature);
|
||||
|
||||
return annots;
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
using AngleSharp.Html;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class RemoveDocStatusHandler : INotificationHandler<RemoveSignatureNotification>
|
||||
{
|
||||
private readonly IRepository<Domain.Entities.DocumentStatus> _repo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public RemoveDocStatusHandler(IRepository<Domain.Entities.DocumentStatus> repository)
|
||||
{
|
||||
_repo = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
|
||||
{
|
||||
notification.ThrowIfHasNoFilter();
|
||||
return _repo.DeleteAsync(statuses =>
|
||||
{
|
||||
// envelope ID filter
|
||||
if (notification.EnvelopeId is int envelopeId)
|
||||
statuses = statuses.Where(status => status.EnvelopeId == envelopeId);
|
||||
|
||||
// envelope UUID filter
|
||||
if (notification.EnvelopeUuid is string envelopeUuid)
|
||||
statuses = statuses.Where(status => status.Envelope!.Uuid == envelopeUuid);
|
||||
|
||||
// receiver Id filter
|
||||
if (notification.ReceiverId is int receiverId)
|
||||
statuses = statuses.Where(status => status.ReceiverId == receiverId);
|
||||
|
||||
// receiver signature filter
|
||||
if (notification.ReceiverSignature is string receiverSignature)
|
||||
statuses = statuses.Where(status => status.Receiver!.Signature == receiverSignature);
|
||||
|
||||
return statuses;
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class RemoveHistoryHandler : INotificationHandler<RemoveSignatureNotification>
|
||||
{
|
||||
private readonly IRepository<Domain.Entities.History> _repo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="repository"></param>
|
||||
public RemoveHistoryHandler(IRepository<Domain.Entities.History> repository)
|
||||
{
|
||||
_repo = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
|
||||
{
|
||||
notification.ThrowIfHasNoFilter();
|
||||
return _repo.DeleteAsync(hists =>
|
||||
{
|
||||
hists = hists.Where(hist => hist.Status == EnvelopeStatus.DocumentSigned);
|
||||
|
||||
// envelope ID filter
|
||||
if (notification.EnvelopeId is int envelopeId)
|
||||
hists = hists.Where(hist => hist.EnvelopeId == envelopeId);
|
||||
|
||||
// envelope UUID filter
|
||||
if (notification.EnvelopeUuid is string envelopeUuid)
|
||||
hists = hists.Where(hist => hist.Envelope!.Uuid == envelopeUuid);
|
||||
|
||||
// receiver ID filter
|
||||
if (notification.ReceiverId is int receiverId)
|
||||
hists = hists.Where(hist => hist.Receiver!.Id == receiverId);
|
||||
|
||||
// receiver signature filter
|
||||
if (notification.ReceiverSignature is string receiverSignature)
|
||||
hists = hists.Where(hist => hist.Receiver!.Signature == receiverSignature);
|
||||
|
||||
return hists;
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="EnvelopeId"></param>
|
||||
/// <param name="ReceiverId"></param>
|
||||
/// <param name="EnvelopeUuid"></param>
|
||||
/// <param name="ReceiverSignature"></param>
|
||||
public record RemoveSignatureNotification(
|
||||
int? EnvelopeId = null,
|
||||
int? ReceiverId = null,
|
||||
string? EnvelopeUuid = null,
|
||||
string? ReceiverSignature = null
|
||||
) : INotification
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool HasFilter =>
|
||||
EnvelopeId is not null
|
||||
|| ReceiverId is not null
|
||||
|| EnvelopeUuid is not null
|
||||
|| ReceiverSignature is not null;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void ThrowIfHasNoFilter()
|
||||
{
|
||||
if (!HasFilter)
|
||||
throw new InvalidOperationException("At least one filter parameter must be provided.");
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
|
||||
using EnvelopeGenerator.Application.Common.Configurations;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface ISendMailNotification : INotification
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public EmailTemplateType TemplateType { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string EmailAddress { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class SendMailHandler<TNotification> : INotificationHandler<TNotification>
|
||||
where TNotification : ISendMailNotification
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly IRepository<EmailTemplate> TempRepo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly IRepository<EmailOut> EmailOutRepo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected abstract Dictionary<string, string> CreatePlaceHolders(TNotification notification);
|
||||
|
||||
/// <summary>
|
||||
///{ "[MESSAGE]", notification.Message },<br/>
|
||||
///{ "[DOCUMENT_ACCESS_CODE]", notification.ReceiverAccessCode },<br/>
|
||||
///{ "[REASON]", pReason }<br/>
|
||||
///{ "[NAME_SENDER]", notification.Envelope.User?.FullName},<br/>
|
||||
///{ "[NAME_PORTAL]", DispatcherParams. },<br/>
|
||||
///{ "[SIGNATURE_TYPE]", "signieren" },<br/>
|
||||
///{ "[LINK_TO_DOCUMENT]", notification.SignatureLink },<br/>
|
||||
///{ "[LINK_TO_DOCUMENT_TEXT]", $"{notification.SignatureLink.Truncate(40)}.." },
|
||||
/// </summary>
|
||||
protected readonly MailParams MailParams;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected readonly DispatcherParams DispatcherParams;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="emailOut"></param>
|
||||
protected abstract void ConfigureEmailOut(TNotification notification, EmailOut emailOut);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="tempRepo"></param>
|
||||
/// <param name="emailOutRepo"></param>
|
||||
/// <param name="mailParamsOptions"></param>
|
||||
/// <param name="dispatcherParamsOptions"></param>
|
||||
protected SendMailHandler(IRepository<EmailTemplate> tempRepo, IRepository<EmailOut> emailOutRepo, IOptions<MailParams> mailParamsOptions, IOptions<DispatcherParams> dispatcherParamsOptions)
|
||||
{
|
||||
TempRepo = tempRepo;
|
||||
EmailOutRepo = emailOutRepo;
|
||||
MailParams = mailParamsOptions.Value;
|
||||
DispatcherParams = dispatcherParamsOptions.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public virtual async Task Handle(TNotification notification, CancellationToken cancel)
|
||||
{
|
||||
var placeHolders = CreatePlaceHolders(notification);
|
||||
|
||||
var temp = await TempRepo
|
||||
.Where(x => x.Name == notification.TemplateType.ToString())
|
||||
.SingleOrDefaultAsync(cancel)
|
||||
?? throw new InvalidOperationException($"Receiver information is missing in the notification." +
|
||||
$"{typeof(TNotification)}:\n {notification.ToJson(Format.Json.ForDiagnostics)}");
|
||||
|
||||
temp.Subject = ReplacePlaceHolders(temp.Subject, placeHolders, MailParams.Placeholders);
|
||||
|
||||
temp.Body = ReplacePlaceHolders(temp.Body, placeHolders, MailParams.Placeholders);
|
||||
|
||||
var emailOut = new EmailOut
|
||||
{
|
||||
EmailAddress = notification.EmailAddress,
|
||||
EmailBody = temp.Body,
|
||||
EmailSubj = temp.Subject,
|
||||
AddedWhen = DateTime.Now,
|
||||
AddedWho = DispatcherParams.AddedWho,
|
||||
SendingProfile = DispatcherParams.SendingProfile,
|
||||
ReminderTypeId = DispatcherParams.ReminderTypeId,
|
||||
EmailAttmt1 = DispatcherParams.EmailAttmt1,
|
||||
WfId = (int)EnvelopeStatus.MessageConfirmationSent,
|
||||
|
||||
};
|
||||
ConfigureEmailOut(notification, emailOut);
|
||||
await EmailOutRepo.CreateAsync(emailOut, cancel);
|
||||
}
|
||||
|
||||
private static string ReplacePlaceHolders(string text, params Dictionary<string, string>[] placeHoldersList)
|
||||
{
|
||||
foreach (var placeHolders in placeHoldersList)
|
||||
foreach (var ph in placeHolders)
|
||||
text = text.Replace(ph.Key, ph.Value);
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Query;
|
||||
|
||||
/// <summary>
|
||||
/// Repräsentiert eine Abfrage für Umschläge.
|
||||
/// </summary>
|
||||
public record EnvelopeQueryBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Die eindeutige Kennung des Umschlags.
|
||||
/// </summary>
|
||||
public virtual int? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Die universell eindeutige Kennung des Umschlags.
|
||||
/// </summary>
|
||||
public virtual string? Uuid { get; set; }
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using DigitalData.Core.Exceptions;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Query;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record EnvelopeReceiverQueryBase : EnvelopeReceiverQueryBase<EnvelopeQueryBase, ReceiverQueryBase>;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnvelopeQuery"></typeparam>
|
||||
/// <typeparam name="TReceiverQuery"></typeparam>
|
||||
public record EnvelopeReceiverQueryBase<TEnvelopeQuery, TReceiverQuery>
|
||||
where TEnvelopeQuery : EnvelopeQueryBase, new()
|
||||
where TReceiverQuery : ReceiverQueryBase, new()
|
||||
{
|
||||
private string? _key;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string? Key
|
||||
{
|
||||
get => _key;
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
_key = null;
|
||||
return;
|
||||
}
|
||||
|
||||
(string? EnvelopeUuid, string? ReceiverSignature) = value.DecodeEnvelopeReceiverId();
|
||||
if (string.IsNullOrEmpty(EnvelopeUuid) || string.IsNullOrEmpty(ReceiverSignature))
|
||||
throw new BadRequestException("Der EnvelopeReceiverKey muss ein gültiger Base64-kodierter String sein, der die EnvelopeUuid und die ReceiverSignature enthält.");
|
||||
|
||||
Envelope = new TEnvelopeQuery()
|
||||
{
|
||||
Uuid = EnvelopeUuid
|
||||
};
|
||||
Receiver = new TReceiverQuery()
|
||||
{
|
||||
Signature = ReceiverSignature
|
||||
};
|
||||
_key = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repräsentiert eine Abfrage für Umschläge.
|
||||
/// </summary>
|
||||
public virtual TEnvelopeQuery Envelope { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
|
||||
/// um spezifische Informationen über einen Empfänger abzurufen.
|
||||
/// </summary>
|
||||
public virtual TReceiverQuery Receiver { get; set; } = new();
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Query;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class MappingProfile : Profile
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public MappingProfile()
|
||||
{
|
||||
CreateMap<EnvelopeQueryBase, Envelope>();
|
||||
CreateMap<ReceiverQueryBase, Receiver>();
|
||||
CreateMap<EnvelopeReceiverQueryBase, EnvelopeReceiver>();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Query;
|
||||
|
||||
/// <summary>
|
||||
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
|
||||
/// um spezifische Informationen über einen Empfänger abzurufen.
|
||||
/// </summary>
|
||||
public record ReceiverQueryBase
|
||||
{
|
||||
/// <summary>
|
||||
/// ID des Empfängers
|
||||
/// </summary>
|
||||
public virtual int? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// E-Mail Adresse des Empfängers
|
||||
/// </summary>
|
||||
public virtual string? EmailAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Eindeutige Signatur des Empfängers
|
||||
/// </summary>
|
||||
public virtual string? Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether any of the specified query criteria have a value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property returns <c>true</c> if at least one of the fields
|
||||
/// <see cref="Id"/>, <see cref="EmailAddress"/>, or <see cref="Signature"/> is not null.
|
||||
/// <para>Usage example: The query can be executed only if at least one criterion is specified.</para>
|
||||
/// </remarks>
|
||||
[NotMapped]
|
||||
public virtual bool HasAnyCriteria => Id is not null || EmailAddress is not null || Signature is not null;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Configurations;
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class DbTriggerParams : Dictionary<string, ICollection<string>>
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Configurations;
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -23,5 +23,5 @@ public class DispatcherParams
|
||||
/// <summary>
|
||||
/// Default value is string.Empty
|
||||
/// </summary>
|
||||
public string? EmailAttmt1 { get; init; } = null;
|
||||
public string EmailAttmt1 { get; init; } = string.Empty;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using DigitalData.Core.Client.Interface;
|
||||
namespace EnvelopeGenerator.Application.Common.Configurations;
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
/// <summary>
|
||||
/// https://www.gtx-messaging.com/en/api-docs/sms-rest-api/
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Configurations;
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,7 +1,7 @@
|
||||
using OtpNet;
|
||||
using System.Globalization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Configurations;
|
||||
namespace EnvelopeGenerator.Application.Configurations;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,7 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,11 +1,11 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use IRepository")]
|
||||
public interface IDocumentReceiverElementRepository : ICRUDRepository<DocReceiverElement, int>
|
||||
public interface IDocumentReceiverElementRepository : ICRUDRepository<DocumentReceiverElement, int>
|
||||
{
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,8 +1,8 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using static EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -0,0 +1,12 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use Read-method returning IReadQuery<TEntity> instead.")]
|
||||
public interface IEnvelopeCertificateRepository : ICRUDRepository<EnvelopeCertificate, int>
|
||||
{
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use IRepository")]
|
||||
public interface IEnvelopeDocumentRepository : ICRUDRepository<Document, int>
|
||||
public interface IEnvelopeDocumentRepository : ICRUDRepository<EnvelopeDocument, int>
|
||||
{
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use IRepository")]
|
||||
public interface IEnvelopeHistoryRepository : ICRUDRepository<History, long>
|
||||
public interface IEnvelopeHistoryRepository : ICRUDRepository<EnvelopeHistory, long>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
@@ -17,7 +17,7 @@ public interface IEnvelopeHistoryRepository : ICRUDRepository<History, long>
|
||||
/// <param name="userReference"></param>
|
||||
/// <param name="status"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, EnvelopeStatus? status = null);
|
||||
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, Constants.EnvelopeStatus? status = null);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -28,5 +28,5 @@ public interface IEnvelopeHistoryRepository : ICRUDRepository<History, long>
|
||||
/// <param name="withSender"></param>
|
||||
/// <param name="withReceiver"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<History>> ReadAsync(int? envelopeId = null, string? userReference = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
|
||||
Task<IEnumerable<EnvelopeHistory>> ReadAsync(int? envelopeId = null, string? userReference = null, Constants.EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,9 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -85,7 +83,7 @@ public interface IEnvelopeReceiverRepository : ICRUDRepository<EnvelopeReceiver,
|
||||
/// <param name="max_status"></param>
|
||||
/// <param name="ignore_statuses"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, params EnvelopeStatus[] ignore_statuses);
|
||||
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,8 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -39,5 +38,5 @@ public interface IEnvelopeRepository : ICRUDRepository<Envelope, int>
|
||||
/// <param name="max_status"></param>
|
||||
/// <param name="ignore_statuses"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<Envelope>> ReadByUserAsync(int userId, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, params EnvelopeStatus[] ignore_statuses);
|
||||
Task<IEnumerable<Envelope>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,7 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Repositories;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Repositories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,6 +1,6 @@
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -14,5 +14,5 @@ public interface IDocumentExecutor
|
||||
/// <param name="envelope_uuid"></param>
|
||||
/// <param name="cancellation"></param>
|
||||
/// <returns></returns>
|
||||
Task<Document> CreateDocumentAsync(string base64, string envelope_uuid, CancellationToken cancellation = default);
|
||||
Task<EnvelopeDocument> CreateDocumentAsync(string base64, string envelope_uuid, CancellationToken cancellation = default);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Dapper;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,6 +1,6 @@
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods for executing common queries on a given entity type.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a raw SQL query contract.
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
|
||||
|
||||
/// <summary>
|
||||
/// Defines methods for executing raw SQL queries or custom SQL query classes and returning query executors for further operations.
|
||||
@@ -1,6 +1,6 @@
|
||||
using Dapper;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor;
|
||||
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,6 +1,6 @@
|
||||
using OtpNet;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,9 +1,9 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,13 +1,13 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use MediatR")]
|
||||
public interface IDocumentReceiverElementService : IBasicCRUDService<DocReceiverElementDto, DocReceiverElement, int>
|
||||
public interface IDocumentReceiverElementService : IBasicCRUDService<DocumentReceiverElementDto, DocumentReceiverElement, int>
|
||||
{
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,10 +1,10 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using static EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use MediatR")]
|
||||
public interface IEnvelopeCertificateService : IBasicCRUDService<EnvelopeCertificateDto, EnvelopeCertificate, int>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use MediatR")]
|
||||
public interface IEnvelopeDocumentService : IBasicCRUDService<EnvelopeDocumentDto, EnvelopeDocument, int>
|
||||
{
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Application.Common.Dto.History;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using static EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use MediatR")]
|
||||
public interface IEnvelopeHistoryService : ICRUDService<HistoryCreateDto, HistoryDto, History, long>
|
||||
public interface IEnvelopeHistoryService : ICRUDService<EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistory, long>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
@@ -56,7 +56,7 @@ public interface IEnvelopeHistoryService : ICRUDService<HistoryCreateDto, Histor
|
||||
/// <param name="withSender"></param>
|
||||
/// <param name="withReceiver"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<HistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
|
||||
Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, EnvelopeStatus? status = null, bool withSender = false, bool withReceiver = false);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -64,14 +64,14 @@ public interface IEnvelopeHistoryService : ICRUDService<HistoryCreateDto, Histor
|
||||
/// <param name="envelopeId"></param>
|
||||
/// <param name="userReference"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<HistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
|
||||
Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="envelopeId"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId);
|
||||
Task<IEnumerable<ReceiverReadDto>> ReadRejectingReceivers(int envelopeId);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,10 +1,10 @@
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Domain;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -19,7 +19,7 @@ public interface IEnvelopeMailService : IEmailOutService
|
||||
/// <param name="tempType"></param>
|
||||
/// <param name="optionalPlaceholders"></param>
|
||||
/// <returns></returns>
|
||||
Task<DataResult<int>> SendAsync(EnvelopeReceiverDto envelopeReceiverDto, EmailTemplateType tempType, Dictionary<string, object>? optionalPlaceholders = null);
|
||||
Task<DataResult<int>> SendAsync(EnvelopeReceiverDto envelopeReceiverDto, Constants.EmailTemplateType tempType, Dictionary<string, object>? optionalPlaceholders = null);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -35,4 +35,11 @@ public interface IEnvelopeMailService : IEmailOutService
|
||||
/// <param name="envelopeReceiverDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto envelopeReceiverDto);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<DataResult<int>> SendTFAQrCodeAsync(EnvelopeReceiverDto envelopeReceiverDto);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,16 +1,13 @@
|
||||
using CommandDotNet;
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Messaging;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
using EnvelopeGenerator.Application.Envelopes;
|
||||
using EnvelopeGenerator.Application.Envelopes.Queries;
|
||||
using EnvelopeGenerator.Application.Receivers.Queries;
|
||||
using EnvelopeGenerator.Domain;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Receivers.Queries.Read;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -123,7 +120,7 @@ public interface IEnvelopeReceiverService : IBasicCRUDService<EnvelopeReceiverDt
|
||||
/// <param name="receiverQuery"></param>
|
||||
/// <param name="ignore_statuses"></param>
|
||||
/// <returns></returns>
|
||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, ReadEnvelopeQuery? envelopeQuery = null, ReadReceiverQuery? receiverQuery = null, params EnvelopeStatus[] ignore_statuses);
|
||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, EnvelopeQuery? envelopeQuery = null, ReadReceiverQuery? receiverQuery = null, params int[] ignore_statuses);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,10 +1,9 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -41,5 +40,5 @@ public interface IEnvelopeService : IBasicCRUDService<EnvelopeDto, Envelope, int
|
||||
/// <param name="max_status"></param>
|
||||
/// <param name="ignore_statuses"></param>
|
||||
/// <returns></returns>
|
||||
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, EnvelopeStatus? min_status = null, EnvelopeStatus? max_status = null, params EnvelopeStatus[] ignore_statuses);
|
||||
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Messaging;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,8 +1,8 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,16 +1,15 @@
|
||||
using DigitalData.Core.Abstraction.Application;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Application.Receivers.Commands;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use MediatR")]
|
||||
public interface IReceiverService : ICRUDService<CreateReceiverCommand, ReceiverDto, Receiver, int>
|
||||
public interface IReceiverService : ICRUDService<ReceiverCreateDto, ReceiverReadDto, Receiver, int>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
@@ -18,7 +17,7 @@ public interface IReceiverService : ICRUDService<CreateReceiverCommand, Receiver
|
||||
/// <param name="emailAddress"></param>
|
||||
/// <param name="signature"></param>
|
||||
/// <returns></returns>
|
||||
Task<DataResult<ReceiverDto>> ReadByAsync(string? emailAddress = null, string? signature = null);
|
||||
Task<DataResult<ReceiverReadDto>> ReadByAsync(string? emailAddress = null, string? signature = null);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -1,6 +1,6 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto.Messaging;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
namespace EnvelopeGenerator.Application.Contracts.Services;
|
||||
|
||||
//TODO: move to DigitalData.Core
|
||||
/// <summary>
|
||||
@@ -1,8 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object representing configuration settings.
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class ConfigDto
|
||||
{
|
||||
/// <summary>
|
||||
@@ -1,12 +1,12 @@
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Interfaces;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object representing a positioned element assigned to a document receiver.
|
||||
/// </summary>
|
||||
public class DocReceiverElementDto : IDocReceiverElement
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class DocumentReceiverElementDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier of the element.
|
||||
@@ -86,40 +86,10 @@ public class DocReceiverElementDto : IDocReceiverElement
|
||||
/// <summary>
|
||||
/// Gets or sets the top position of the element (in layout terms).
|
||||
/// </summary>
|
||||
public double Top => Y;
|
||||
public double Top { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the left position of the element (in layout terms).
|
||||
/// </summary>
|
||||
public double Left => X;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IEnumerable<AnnotationDto>? Annotations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SenderAppType SenderAppType { get; set; } = SenderAppType.LegacyFormApp;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? FullName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? Place { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public byte[]? Ink { get; set; }
|
||||
public double Left { get; set; }
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object representing the status of a document for a specific receiver.
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class DocumentStatusDto
|
||||
{
|
||||
/// <summary>
|
||||
@@ -25,7 +26,7 @@ public class DocumentStatusDto
|
||||
/// <summary>
|
||||
/// Gets or sets the current status code.
|
||||
/// </summary>
|
||||
public EnvelopeStatus Status { get; set; }
|
||||
public int Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp when the status was changed.
|
||||
31
EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs
Normal file
31
EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record EmailTemplateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int Id{ get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required string Subject { get; set; }
|
||||
};
|
||||
}
|
||||
50
EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs
Normal file
50
EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object representing certificate information for an envelope.
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class EnvelopeCertificateDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the unique identifier of the certificate.
|
||||
/// </summary>
|
||||
public int Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the envelope ID associated with the certificate.
|
||||
/// </summary>
|
||||
public int EnvelopeId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UUID of the envelope.
|
||||
/// </summary>
|
||||
public string EnvelopeUuid { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subject of the envelope.
|
||||
/// </summary>
|
||||
public string EnvelopeSubject { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ID of the creator of the envelope.
|
||||
/// </summary>
|
||||
public int CreatorId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the creator.
|
||||
/// </summary>
|
||||
public string CreatorName { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the email address of the creator.
|
||||
/// </summary>
|
||||
public string CreatorEmail { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current status of the envelope.
|
||||
/// </summary>
|
||||
public int EnvelopeStatus { get; init; }
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object representing a document within an envelope, including optional binary data and form elements.
|
||||
/// </summary>
|
||||
public class DocumentDto
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class EnvelopeDocumentDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier of the document.
|
||||
@@ -28,5 +31,5 @@ public class DocumentDto
|
||||
/// <summary>
|
||||
/// Gets or sets the collection of elements associated with the document for receiver interactions, if any.
|
||||
/// </summary>
|
||||
public IEnumerable<DocReceiverElementDto>? Elements { get; set; }
|
||||
public IEnumerable<DocumentReceiverElementDto>? Elements { get; set; }
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Dto.History;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Domain.Interfaces;
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record EnvelopeDto : IEnvelope
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record EnvelopeDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
@@ -25,7 +24,7 @@ public record EnvelopeDto : IEnvelope
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required EnvelopeStatus Status { get; set; }
|
||||
public int Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default value is string.Empty
|
||||
@@ -74,13 +73,6 @@ public record EnvelopeDto : IEnvelope
|
||||
/// </summary>
|
||||
public int? EnvelopeTypeId { get; set; }
|
||||
|
||||
// TODO: use ReadAndConfirm property name
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Obsolete("Use EnvelopeExtensions.IsReadAndConfirm extension metot instead.")]
|
||||
public bool ReadOnly => this.IsReadAndConfirm();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@@ -89,7 +81,7 @@ public record EnvelopeDto : IEnvelope
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool UseAccessCode { get; set; } = true;
|
||||
public bool? UseAccessCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -124,15 +116,5 @@ public record EnvelopeDto : IEnvelope
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IEnumerable<DocumentDto>? Documents { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IEnumerable<EnvelopeReceiverDto>? EnvelopeReceivers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Envelope history entries tracking actions like DocumentSigned, EnvelopeOpened, etc.
|
||||
/// </summary>
|
||||
public IEnumerable<HistoryDto>? Histories { get; set; }
|
||||
public IEnumerable<EnvelopeDocumentDto>? Documents { get; set; }
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.History;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object for creating a new envelope history record.
|
||||
/// </summary>
|
||||
public class HistoryCreateDto
|
||||
public class EnvelopeHistoryCreateDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the identifier of the envelope.
|
||||
@@ -1,13 +1,13 @@
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using static EnvelopeGenerator.Domain.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.History;
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object representing the history of an envelope, including status, sender, receiver, and related metadata.
|
||||
/// </summary>
|
||||
public record HistoryDto
|
||||
public record EnvelopeHistoryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for the envelope history entry.
|
||||
@@ -25,19 +25,9 @@ public record HistoryDto
|
||||
public required string UserReference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Include code of the envelope at this history point.
|
||||
/// Status code of the envelope at this history point.
|
||||
/// </summary>
|
||||
public EnvelopeStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of reference for this history entry.
|
||||
/// </summary>
|
||||
public ReferenceType ReferenceType => ((int)Status).ToString().FirstOrDefault() switch
|
||||
{
|
||||
'1' => ReferenceType.Sender,
|
||||
'2' => ReferenceType.Receiver,
|
||||
_ => ReferenceType.System,
|
||||
};
|
||||
public int Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable name of the status.
|
||||
@@ -62,7 +52,12 @@ public record HistoryDto
|
||||
/// <summary>
|
||||
/// Information about the receiver associated with this history entry.
|
||||
/// </summary>
|
||||
public ReceiverDto? Receiver { get; set; }
|
||||
public ReceiverReadDto? Receiver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of reference for this history entry.
|
||||
/// </summary>
|
||||
public ReferenceType ReferenceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment related to this history entry.
|
||||
@@ -1,24 +1,14 @@
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record EnvelopeReceiverDto
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record EnvelopeReceiverBasicDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public EnvelopeDto? Envelope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ReceiverDto? Receiver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@@ -60,11 +50,6 @@ public record EnvelopeReceiverDto
|
||||
/// </summary>
|
||||
public string? PrivateMessage { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? AccessCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@@ -79,13 +64,4 @@ public record EnvelopeReceiverDto
|
||||
///
|
||||
/// </summary>
|
||||
public bool HasPhoneNumber { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this receiver has signed the envelope.
|
||||
/// Checks if there is a DocumentSigned history entry for this receiver in the envelope's history.
|
||||
/// </summary>
|
||||
public bool Signed => Envelope?.Histories?.Any(h =>
|
||||
h.Receiver?.Id == ReceiverId &&
|
||||
h.Status == EnvelopeStatus.DocumentSigned
|
||||
) ?? false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record EnvelopeReceiverDto() : EnvelopeReceiverBasicDto()
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public EnvelopeDto? Envelope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ReceiverReadDto? Receiver { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record EnvelopeReceiverSecretDto : EnvelopeReceiverDto
|
||||
{
|
||||
/// <summary>
|
||||
@@ -1,12 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="DateValid"></param>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record EnvelopeReceiverReadOnlyCreateDto(
|
||||
DateTime DateValid)
|
||||
{
|
||||
@@ -1,11 +1,13 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a read-only Data Transfer Object (DTO) for an envelope receiver.
|
||||
/// Contains information about the receiver, associated envelope, and audit details.
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class EnvelopeReceiverReadOnlyDto
|
||||
{
|
||||
/// <summary>
|
||||
@@ -57,5 +59,5 @@ public class EnvelopeReceiverReadOnlyDto
|
||||
/// <summary>
|
||||
/// Gets or inits the associated receiver details.
|
||||
/// </summary>
|
||||
public ReceiverDto? Receiver { get; set; }
|
||||
public ReceiverReadDto? Receiver { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object for updating a read-only envelope receiver.
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class EnvelopeReceiverReadOnlyUpdateDto
|
||||
{
|
||||
/// <summary>
|
||||
@@ -1,8 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Data Transfer Object representing a type of envelope with its configuration settings.
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class EnvelopeTypeDto
|
||||
{
|
||||
/// <summary>
|
||||
68
EnvelopeGenerator.Application/DTOs/MappingProfile.cs
Normal file
68
EnvelopeGenerator.Application/DTOs/MappingProfile.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using AutoMapper;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the AutoMapper profile configuration for mapping between
|
||||
/// domain entities and data transfer objects (DTOs) used within the EnvelopeGenerator application.
|
||||
/// </summary>
|
||||
public class MappingProfile : Profile
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MappingProfile"/> class.
|
||||
/// Configures the mappings between entities and DTOs used throughout the application.
|
||||
/// </summary>
|
||||
public MappingProfile()
|
||||
{
|
||||
// Entity to DTO mappings
|
||||
CreateMap<Config, ConfigDto>();
|
||||
CreateMap<DocumentReceiverElement, DocumentReceiverElementDto>();
|
||||
CreateMap<DocumentStatus, DocumentStatusDto>();
|
||||
CreateMap<EmailTemplate, EmailTemplateDto>();
|
||||
CreateMap<Envelope, EnvelopeDto>();
|
||||
CreateMap<EnvelopeCertificate, EnvelopeCertificateDto>();
|
||||
CreateMap<EnvelopeDocument, EnvelopeDocumentDto>();
|
||||
CreateMap<Domain.Entities.EnvelopeHistory, EnvelopeHistoryDto>();
|
||||
CreateMap<Domain.Entities.EnvelopeHistory, EnvelopeHistoryCreateDto>();
|
||||
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverDto>();
|
||||
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverSecretDto>();
|
||||
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
||||
CreateMap<Domain.Entities.Receiver, ReceiverReadDto>();
|
||||
CreateMap<Domain.Entities.Receiver, ReceiverCreateDto>();
|
||||
CreateMap<Domain.Entities.Receiver, ReceiverUpdateDto>();
|
||||
CreateMap<Domain.Entities.EnvelopeReceiverReadOnly, EnvelopeReceiverReadOnlyDto>();
|
||||
|
||||
// DTO to Entity mappings
|
||||
CreateMap<ConfigDto, Config>();
|
||||
CreateMap<DocumentReceiverElementDto, DocumentReceiverElement>();
|
||||
CreateMap<DocumentStatusDto, DocumentStatus>();
|
||||
CreateMap<EmailTemplateDto, EmailTemplate>();
|
||||
CreateMap<EnvelopeDto, Envelope>();
|
||||
CreateMap<EnvelopeCertificateDto, EnvelopeCertificate>();
|
||||
CreateMap<EnvelopeDocumentDto, EnvelopeDocument>();
|
||||
CreateMap<EnvelopeHistoryDto, Domain.Entities.EnvelopeHistory>();
|
||||
CreateMap<EnvelopeHistoryCreateDto, Domain.Entities.EnvelopeHistory>();
|
||||
CreateMap<EnvelopeReceiverDto, Domain.Entities.EnvelopeReceiver>();
|
||||
CreateMap<EnvelopeTypeDto, EnvelopeType>();
|
||||
CreateMap<ReceiverReadDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
|
||||
CreateMap<ReceiverCreateDto, Domain.Entities.Receiver>();
|
||||
CreateMap<ReceiverUpdateDto, Domain.Entities.Receiver>();
|
||||
CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverBasicDto>();
|
||||
CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||
|
||||
// Messaging mappings
|
||||
// for GTX messaging
|
||||
CreateMap<GtxMessagingResponse, SmsResponse>()
|
||||
.ConstructUsing(gtxRes => gtxRes.Ok()
|
||||
? new SmsResponse() { Ok = true }
|
||||
: new SmsResponse() { Ok = false, Errors = gtxRes });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class GtxMessagingResponse : Dictionary<string, object?> { }
|
||||
@@ -1,8 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.Messaging;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.Messaging;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record SmsResponse
|
||||
{
|
||||
/// <summary>
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public record ReceiverCreateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ReceiverCreateDto()
|
||||
{
|
||||
_sha256HexOfMail = new(() =>
|
||||
{
|
||||
var bytes_arr = Encoding.UTF8.GetBytes(EmailAddress!.ToUpper());
|
||||
var hash_arr = SHA256.HashData(bytes_arr);
|
||||
var hexa_str = BitConverter.ToString(hash_arr);
|
||||
return hexa_str.Replace("-", string.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[EmailAddress]
|
||||
public required string EmailAddress { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? TotpSecretkey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// var bytes_arr = Encoding.UTF8.GetBytes(EmailAddress.ToUpper());<br/>
|
||||
/// var hash_arr = SHA256.HashData(bytes_arr);
|
||||
/// var hexa_str = BitConverter.ToString(hash_arr);
|
||||
/// return hexa_str.Replace("-", string.Empty);
|
||||
/// </summary>
|
||||
public string Signature => _sha256HexOfMail.Value;
|
||||
|
||||
private readonly Lazy<string> _sha256HexOfMail;
|
||||
|
||||
/// <summary>
|
||||
/// Default value is DateTime.Now
|
||||
/// </summary>
|
||||
public DateTime AddedWhen { get; } = DateTime.Now;
|
||||
};
|
||||
@@ -1,12 +1,14 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Dto.Receiver;
|
||||
namespace EnvelopeGenerator.Application.DTOs.Receiver;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ReceiverDto
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class ReceiverReadDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
@@ -23,12 +25,6 @@ public class ReceiverDto
|
||||
/// </summary>
|
||||
public required string Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string? TotpSecretkey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@@ -38,13 +34,18 @@ public class ReceiverDto
|
||||
///
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public IEnumerable<EnvelopeReceiverDto>? EnvelopeReceivers { get; set; }
|
||||
public IEnumerable<EnvelopeReceiverBasicDto>? EnvelopeReceivers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? LastUsedName => EnvelopeReceivers?.LastOrDefault()?.Name;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string? TotpSecretkey { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user