Compare commits

..

8 Commits

Author SHA1 Message Date
b8c00884a9 Merge EnvelopeReceiver and EnvelopeReceiverBase 2025-08-13 16:35:51 +02:00
51d49d68ba fix(Envelope): Fügen Nicht-relationalen Eigenschaften NotMapped-Attribute hinzu. 2025-08-13 16:07:26 +02:00
4d5ee2b461 fix(MailParams): make Placeholders Dictionary 2025-08-13 13:03:56 +02:00
8a79ee4126 Stil: BaseController auf Datei-Namensraumformat umstellen 2025-08-12 11:24:38 +02:00
cde9896c01 Merge branch 'master' of http://git.dd:3000/AppStd/EnvelopeGenerator 2025-08-07 17:01:51 +02:00
c7d26a87b0 fix(EnvelopeMailService): Vermeiden Sie gemeinsam genutzte veränderbare Zustände in EnvelopeMailService-Platzhaltern
EnvelopeMailService wurde umgestaltet, um gemeinsam genutzte Veränderungen des _placeholders-Wörterbuchs zu vermeiden.
Die Konfigurationseigenschaft MailParams.Placeholders wurde von einem veränderbaren Dictionary<string, string>
zu einem ImmutableDictionary<string, string> geändert, und _placeholders wird nun bei der Dienstkonstruktion als neues Wörterbuch instanziiert.
2025-08-07 17:01:32 +02:00
17ceb1f72a Update EnvelopeGenerator.Web/wwwroot/README.md 2025-08-06 09:48:34 +02:00
b2c396c3b2 Add EnvelopeGenerator.Web/wwwroot/README.md 2025-08-06 09:45:11 +02:00
7 changed files with 144 additions and 76 deletions

View File

@@ -54,7 +54,7 @@ public class MappingProfile : Profile
CreateMap<ReceiverReadDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore()); CreateMap<ReceiverReadDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
CreateMap<ReceiverCreateDto, Domain.Entities.Receiver>(); CreateMap<ReceiverCreateDto, Domain.Entities.Receiver>();
CreateMap<ReceiverUpdateDto, Domain.Entities.Receiver>(); CreateMap<ReceiverUpdateDto, Domain.Entities.Receiver>();
CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>(); CreateMap<Domain.Entities.EnvelopeReceiver, EnvelopeReceiverBasicDto>();
CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>(); CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>(); CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>();

View File

@@ -44,11 +44,11 @@ private readonly IAuthenticator _authenticator;
public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherParams> dispatcherConfigOptions, IConfigService configService, IOptions<MailParams> mailConfig, IAuthenticator authenticator) : base(repository, mapper) public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherParams> dispatcherConfigOptions, IConfigService configService, IOptions<MailParams> mailConfig, IAuthenticator authenticator) : base(repository, mapper)
{ {
_tempService = tempService; _tempService = tempService;
_envRcvService = envelopeReceiverService; _envRcvService = envelopeReceiverService;
_dConfig = dispatcherConfigOptions.Value; _dConfig = dispatcherConfigOptions.Value;
_configService = configService; _configService = configService;
_placeholders = mailConfig.Value.Placeholders; _placeholders = new Dictionary<string, string>(mailConfig.Value.Placeholders);
_authenticator = authenticator; _authenticator = authenticator;
} }
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null) private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)

View File

@@ -138,12 +138,15 @@ namespace EnvelopeGenerator.Domain.Entities
public byte[] DOC_RESULT { get; set; } public byte[] DOC_RESULT { get; set; }
// TODO: * Check the Form App and remove the default value // TODO: * Check the Form App and remove the default value
[NotMapped]
public List<EnvelopeDocument> Documents { get; set; } = new List<EnvelopeDocument>(); public List<EnvelopeDocument> Documents { get; set; } = new List<EnvelopeDocument>();
// TODO: * Check the Form App and remove the default value // TODO: * Check the Form App and remove the default value
[NotMapped]
public List<EnvelopeHistory> History { get; set; } = new List<EnvelopeHistory>(); public List<EnvelopeHistory> History { get; set; } = new List<EnvelopeHistory>();
// TODO: * Check the Form App and remove the default value // TODO: * Check the Form App and remove the default value
[NotMapped]
public List<Receiver> Receivers { get; set; } = new List<Receiver>(); public List<Receiver> Receivers { get; set; } = new List<Receiver>();
/// <summary> /// <summary>

View File

@@ -1,10 +1,59 @@
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#if NETFRAMEWORK
using System;
#endif
namespace EnvelopeGenerator.Domain.Entities namespace EnvelopeGenerator.Domain.Entities
{ {
[Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")] [Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")]
public class EnvelopeReceiver : EnvelopeReceiverBase public class EnvelopeReceiver
{ {
[Key]
[Column("ENVELOPE_ID")]
public int EnvelopeId { get; set; }
[Key]
[Column("RECEIVER_ID")]
public int ReceiverId { get; set; }
[Required]
[Column("SEQUENCE")]
public int Sequence { get; set; }
[Column("NAME", TypeName = "nvarchar(128)")]
public string Name { get; set; }
[Column("JOB_TITLE", TypeName = "nvarchar(128)")]
public string JobTitle { get; set; }
[Column("COMPANY_NAME", TypeName = "nvarchar(128)")]
public string CompanyName { get; set; }
[Column("PRIVATE_MESSAGE", TypeName = "nvarchar(max)")]
public string PrivateMessage { get; set; }
[Column("ACCESS_CODE", TypeName = "nvarchar(64)")]
public string AccessCode { get; set; }
[Required]
[Column("ADDED_WHEN", TypeName = "datetime")]
public DateTime AddedWhen { get; set; }
[Column("CHANGED_WHEN", TypeName = "datetime")]
public DateTime ChangedWhen { get; set; }
[Column("PHONE_NUMBER")]
[StringLength(20)]
[RegularExpression(@"^\+[0-9]+$", ErrorMessage = "Phone number must start with '+' followed by digits.")]
public string PhoneNumber { get; set; }
[NotMapped]
public Tuple<int, int> Id => Tuple.Create(EnvelopeId, ReceiverId);
[NotMapped]
public bool HasPhoneNumber => !string.IsNullOrWhiteSpace(PhoneNumber);
[ForeignKey("EnvelopeId")] [ForeignKey("EnvelopeId")]
public Envelope Envelope { get; set; } public Envelope Envelope { get; set; }

View File

@@ -1,57 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#if NETFRAMEWORK
using System;
#endif
namespace EnvelopeGenerator.Domain.Entities
{
[Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")]
public class EnvelopeReceiverBase
{
[Key]
[Column("ENVELOPE_ID")]
public int EnvelopeId { get; set; }
[Key]
[Column("RECEIVER_ID")]
public int ReceiverId { get; set; }
[Required]
[Column("SEQUENCE")]
public int Sequence { get; set; }
[Column("NAME", TypeName = "nvarchar(128)")]
public string Name { get; set; }
[Column("JOB_TITLE", TypeName = "nvarchar(128)")]
public string JobTitle { get; set; }
[Column("COMPANY_NAME", TypeName = "nvarchar(128)")]
public string CompanyName { get; set; }
[Column("PRIVATE_MESSAGE", TypeName = "nvarchar(max)")]
public string PrivateMessage { get; set; }
[Column("ACCESS_CODE", TypeName = "nvarchar(64)")]
public string AccessCode { get; set; }
[Required]
[Column("ADDED_WHEN", TypeName = "datetime")]
public DateTime AddedWhen { get; set; }
[Column("CHANGED_WHEN", TypeName = "datetime")]
public DateTime ChangedWhen { get; set; }
[Column("PHONE_NUMBER")]
[StringLength(20)]
[RegularExpression(@"^\+[0-9]+$", ErrorMessage = "Phone number must start with '+' followed by digits.")]
public string PhoneNumber { get; set; }
[NotMapped]
public Tuple<int, int> Id => Tuple.Create(EnvelopeId, ReceiverId);
[NotMapped]
public bool HasPhoneNumber => !string.IsNullOrWhiteSpace(PhoneNumber);
}
}

View File

@@ -1,18 +1,17 @@
using EnvelopeGenerator.Web.Services; using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Web.Controllers namespace EnvelopeGenerator.Web.Controllers;
public class BaseController : Controller
{ {
public class BaseController : Controller protected readonly DatabaseService database;
protected readonly ILogger _logger;
public BaseController(DatabaseService database, ILogger logger)
{ {
protected readonly DatabaseService database; this.database = database;
_logger = logger;
protected readonly ILogger _logger;
public BaseController(DatabaseService database, ILogger logger)
{
this.database = database;
_logger = logger;
}
} }
} }

View File

@@ -0,0 +1,74 @@
# 📄 PSPDFKit-Integration Vanilla JavaScript
Dieses Projekt zeigt, wie die PDF-Anzeige- und Signaturbibliothek [PSPDFKit](https://www.nutrient.io/sdk/web/getting-started/other-frameworks/javascript/) mithilfe von **Vanilla JavaScript** integriert werden kann.
## 🚀 Verwendungszweck
PSPDFKit wurde in der Webanwendung verwendet, um PDF-Dokumente:
- anzuzeigen,
- zu signieren,
- mit Anmerkungen zu versehen,
- Formularfelder auszufüllen.
Benutzer können Dokumente **direkt über den Browser signieren und versenden**.
---
## 🔧 Wo und wie wurde PSPDFKit verwendet?
### 1. PSPDFKit laden
PSPDFKit wurde mit der Funktion `loadPSPDFKit` in `UI.js` gestartet:
```js
PSPDFKit.load({
container: #app,
document: arrayBuffer,
licenseKey: YOUR_LICENSE_KEY,
...
})
```
### 2. Anmerkungen und Formularfelder
In `annotation.js` werden die folgenden Felder dynamisch zu PDF-Dokumenten hinzugefügt:
- **Signaturfeld** (`SignatureFormField`)
- **Position** (`TextFormField`)
- **Stadt** (`TextFormField`)
- **Datum** (`TextFormField`, wird automatisch mit dem heutigen Datum ausgefüllt)
- **Bezeichnungen** (`Ort`, `Position`, `Date`) dies sind nur lesbare Textfelder.
- **Rahmen für Signaturbild** wird dynamisch erstellt und platziert, wenn der Benutzer unterschreibt.
Die Felder werden entsprechend ihrer Position auf dem PDF berechnet und für jedes Feld wird eine eindeutige ID erstellt.
---
### 3. Anpassungen der Symbolleiste
In `UI.js` ist die Standard-Symbolleiste (`toolbarItems`) von PSPDFKit konfiguriert:
- Es werden nur zulässige Elemente (`sidebar`, `zoom`, `pager`, `search` usw.) angezeigt.
- Je nach Benutzerberechtigung (z. B. schreibgeschützt oder beschreibbar) werden die folgenden speziellen Schaltflächen dynamisch hinzugefügt:
**Beschreibbarer Modus:**
- `Teilen` (SHARE)
- `Logout` (LOGOUT)
- `Zurücksetzen` (RESET)
- `Ablehnen` (REJECT)
- `Finalisieren` (FINISH)
**Nur-Lesemodus:**
- Die Schaltfläche `Teilen` kopiert nur den Link in die Zwischenablage (COPY_URL)
Für mobile Geräte werden zusätzlich vereinfachte Schaltflächen angezeigt.
---
### 📁 Wichtige Dateien
| Datei | Beschreibung |
|-------------------|-----------------------------------------------|
| `app.js` | Hauptanwendungsklasse, Dokumentladen und -steuerung |
| `ui.js` | PSPDFKit-UI-Einrichtung und Symbolleistenverwaltung |
| `annotation.js` | Erstellen und Löschen von Anmerkungsfeldern |