Compare commits

...

9 Commits

Author SHA1 Message Date
Developer 02
939ba1bb47 feat: Sortierung der Tabelle hinzugefügt 2024-08-30 23:38:02 +02:00
Developer 02
d5de868eb9 feat: added filter and paginator 2024-08-30 23:25:22 +02:00
Developer 02
6e3bb6c3a0 feat: Enhance receiver input and table components
- Updated `ReceiverInputComponent` to support optional index parameter in the `filter` function to manage email input logic more effectively.
- Added `last_used_name` functionality in `ReceiverTableComponent` to auto-fill names based on the last used email name.
- Implemented email duplication prevention logic in `ReceiverTableComponent` to ensure unique email inputs.
- Refactored component lifecycle methods and data handling for improved performance and user experience.
2024-08-30 22:25:13 +02:00
Developer 02
d347ec420c feat: ReadAllAsync-Methode zur ReceiverRepository hinzugefügt
- `ReadAllAsync`-Methode hinzugefügt, um alle `Receiver`-Entitäten asynchron zurückzugeben.
- Stellt sicher, dass alle Empfänger abgerufen werden, während die vorhandene Abfragelogik mit `ReadBy` erhalten bleibt.
2024-08-30 11:58:00 +02:00
Developer 02
a011b677ea refactor: EnvelopeReceiver-Klasse refaktoriert, um eine Endlosschleife zu verhindern und die Datenabfrage zu verbessern
- `EnvelopeReceiver` in `EnvelopeReceiver` und `EnvelopeReceiverBase` aufgeteilt, um zirkuläre Abhängigkeiten zu vermeiden.
- `EnvelopeReceiverBasicDto` für vereinfachte Datenübertragungsobjekte erstellt.
- `ReceiverRepository` aktualisiert, um den zuletzt verwendeten Empfängernamen durch das Laden aktueller `EnvelopeReceiver`-Daten einzubeziehen.
- `ReceiverReadDto` angepasst, um `LastUsedName` zu erhalten und `EnvelopeReceivers` für die JSON-Serialisierung zu ignorieren.
2024-08-30 11:27:36 +02:00
Developer 02
8831436809 feat(controller): add endpoint to retrieve last used receiver name by email
- Implemented `Get` endpoint in `EnvelopeReceiverController` to fetch the last used receiver's name by email.
- Added handling for successful and failed responses, including proper status codes and logging.
2024-08-29 17:15:00 +02:00
Developer 02
1ededc1f64 feat(service): add ReadLastUsedReceiverNameByMail method to IEnvelopeReceiverService and EnvelopeReceiverService
- Added `ReadLastUsedReceiverNameByMail` method to `IEnvelopeReceiverService` interface.
- Implemented `ReadLastUsedReceiverNameByMail` method in `EnvelopeReceiverService` to retrieve the last used receiver's name by email and handle results with `DataResult`.
2024-08-29 16:57:45 +02:00
Developer 02
183c94fd0a Merge branch 'master' into feat/signFlow-gen 2024-08-29 16:49:30 +02:00
Developer 02
a0a5568d93 feat(repository): Methode ReadLastByReceiver zu IEnvelopeReceiverRepository und EnvelopeReceiverRepository hinzugefügt
- Methode `ReadLastByReceiver` zum Interface `IEnvelopeReceiverRepository` hinzugefügt.
- Methode `ReadLastByReceiver` in `EnvelopeReceiverRepository` implementiert, um den letzten `EnvelopeReceiver` anhand der E-Mail-Adresse abzurufen.
2024-08-29 16:04:19 +02:00
28 changed files with 247 additions and 165 deletions

View File

@@ -1,6 +1,6 @@
using DigitalData.Core.DTO;
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Common;
namespace EnvelopeGenerator.Application.Contracts

View File

@@ -1,6 +1,6 @@
using DigitalData.Core.Abstractions.Application;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Contracts
@@ -25,5 +25,7 @@ namespace EnvelopeGenerator.Application.Contracts
Task<DataResult<bool>> IsExisting(string envelopeReceiverId);
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail);
}
}

View File

@@ -0,0 +1,26 @@
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
{
public record EnvelopeReceiverBasicDto()
{
public int EnvelopeId { get; init; }
public int ReceiverId { get; init; }
public int Sequence { get; init; }
[TemplatePlaceholder("[NAME_RECEIVER]")]
public string? Name { get; init; }
public string? JobTitle { get; init; }
public string? CompanyName { get; init; }
public string? PrivateMessage { get; init; }
public DateTime AddedWhen { get; init; }
public DateTime? ChangedWhen { get; init; }
}
}

View File

@@ -0,0 +1,11 @@
using EnvelopeGenerator.Application.DTOs.Receiver;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
{
public record EnvelopeReceiverDto() : EnvelopeReceiverBasicDto()
{
public EnvelopeDto? Envelope { get; set; }
public ReceiverReadDto? Receiver { get; set; }
}
}

View File

@@ -1,31 +0,0 @@
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
using EnvelopeGenerator.Application.DTOs.Receiver;
namespace EnvelopeGenerator.Application.DTOs
{
public record EnvelopeReceiverDto()
{
public int EnvelopeId { get; set; }
public int ReceiverId { get; set; }
public int Sequence { get; set; }
[TemplatePlaceholder("[NAME_RECEIVER]")]
public string? Name { get; set; }
public string? JobTitle { get; set; }
public string? CompanyName { get; set; }
public string? PrivateMessage { get; set; }
public DateTime AddedWhen { get; set; }
public DateTime? ChangedWhen { get; set; }
public EnvelopeDto? Envelope { get; set; }
public ReceiverReadDto? Receiver { get; set; }
}
}

View File

@@ -1,4 +1,6 @@
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using System.Text.Json.Serialization;
namespace EnvelopeGenerator.Application.DTOs.Receiver
{
@@ -6,6 +8,12 @@ namespace EnvelopeGenerator.Application.DTOs.Receiver
int Id,
string EmailAddress,
string Signature,
DateTime AddedWhen
) : BaseDTO<int>(Id);
DateTime AddedWhen
) : BaseDTO<int>(Id)
{
[JsonIgnore]
public IEnumerable<EnvelopeReceiverBasicDto>? EnvelopeReceivers { get; init; }
public string? LastUsedName => EnvelopeReceivers?.LastOrDefault()?.Name;
};
}

View File

@@ -14,7 +14,7 @@
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="DigitalData.Core.Abstractions" Version="1.0.1.1" />
<PackageReference Include="DigitalData.Core.Application" Version="1.0.0" />
<PackageReference Include="DigitalData.Core.DTO" Version="1.0.0" />
<PackageReference Include="DigitalData.Core.DTO" Version="1.0.0.1" />
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
<PackageReference Include="UserManager.Application" Version="1.0.0" />

View File

@@ -1,6 +1,7 @@
using AutoMapper;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Application.DTOs.Receiver;
using EnvelopeGenerator.Domain.Entities;
@@ -43,6 +44,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles
CreateMap<ReceiverCreateDto, Receiver>();
CreateMap<ReceiverUpdateDto, Receiver>();
CreateMap<UserReceiverDto, UserReceiver>();
CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>();
}
}
}

View File

@@ -5,7 +5,7 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut;
using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
using DigitalData.UserManager.Application;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Common;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
@@ -14,7 +14,7 @@ using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Application.Services
{
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
{
private readonly IEmailTemplateService _tempService;
private readonly IEnvelopeReceiverService _envRcvService;

View File

@@ -2,7 +2,7 @@
using DigitalData.Core.Application;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Application.Resources;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
@@ -122,5 +122,11 @@ namespace EnvelopeGenerator.Application.Services
var dto_list = _mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(er_list);
return Result.Success(dto_list);
}
public async Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail)
{
var er = await _repository.ReadLastByReceiver(mail);
return er is null ? Result.Fail<string?>().Notice(LogLevel.None, Flag.NotFound) : Result.Success(er.Name);
}
}
}

View File

@@ -1,45 +1,10 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations.Schema;
namespace EnvelopeGenerator.Domain.Entities
{
[Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")]
public class EnvelopeReceiver
public class EnvelopeReceiver : 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; }
[ForeignKey("EnvelopeId")]
public Envelope? Envelope { get; set; }

View File

@@ -0,0 +1,43 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
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; }
}
}

View File

@@ -22,5 +22,7 @@ namespace EnvelopeGenerator.Domain.Entities
[Required]
[Column("ADDED_WHEN", TypeName = "datetime")]
public DateTime AddedWhen { get; set; }
public IEnumerable<EnvelopeReceiver>? EnvelopeReceivers { get; init; }
}
}

View File

@@ -1,8 +1,13 @@
<table #table mat-table [dataSource]="data" class="mat-elevation-z8">
<mat-form-field>
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. ium" #input>
</mat-form-field>
<table #table mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort>
@for (colId of displayedColumns; track colId) {
<ng-container matColumnDef="{{colId}}">
<th mat-header-cell *matHeaderCellDef> {{schema[colId].header}} </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{schema[colId].header}} </th>
<td mat-cell *matCellDef="let element"> {{schema[colId].field(element)}} </td>
</ng-container>
}
@@ -22,22 +27,7 @@
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
<div class="example-element-detail" [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<div class="example-element-diagram">
<div class="example-element-position"> {{"element.position"}} </div>
<div class="example-element-symbol"> {{"element.symbol"}} </div>
<div class="example-element-name"> {{"element.name"}} </div>
<div class="example-element-weight"> {{"element.weight"}} </div>
</div>
<div class="example-element-description">
{{"element.description"}}
<span class="example-element-description-attribution"> -- Wikipedia </span>
</div>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;" class="example-element-row"
@@ -45,4 +35,5 @@
(click)="expandedElement = expandedElement === element ? null : element">
</tr>
<!--<tr mat-row *matRowDef="let row; columns: ['expandedDetail']; when: isExpandedRow" class="example-detail-row"></tr>-->
</table>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" aria-label="Select page of users"></mat-paginator>

View File

@@ -1,31 +1,10 @@
.example-element-row td {
border-bottom-width: 0;
}
.example-element-detail {
overflow: hidden;
display: flex;
}
.example-element-diagram {
min-width: 80px;
border: 2px solid black;
padding: 8px;
font-weight: lighter;
margin: 8px 0;
height: 104px;
}
.example-element-symbol {
font-weight: bold;
font-size: 40px;
line-height: normal;
}
.example-element-description {
padding: 16px;
}
.example-element-description-attribution {
opacity: 0.5;
}
/* Structure */
table {
width: 100%;
}
.mat-mdc-form-field {
font-size: 14px;
width: 100%;
margin-top: 10px;
}

View File

@@ -1,15 +1,19 @@
import { Component, Input, ViewChild } from '@angular/core';
import { AfterViewInit, Component, Input, ViewChild } from '@angular/core';
import { EnvelopeReceiverService } from '../../services/envelope-receiver.service';
import { MatTable, MatTableModule } from '@angular/material/table';
import { MatTable, MatTableModule, MatTableDataSource } from '@angular/material/table';
import { CommonModule } from '@angular/common'
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import {MatPaginator, MatPaginatorModule} from '@angular/material/paginator';
import {MatSort, MatSortModule} from '@angular/material/sort';
@Component({
selector: 'app-envelope-table',
standalone: true,
imports: [MatTableModule, CommonModule, MatTableModule, MatButtonModule, MatIconModule],
imports: [MatTableModule, CommonModule, MatTableModule, MatButtonModule, MatIconModule, MatFormFieldModule, MatInputModule, MatTableModule, MatPaginator, MatPaginatorModule, MatSort, MatSortModule],
templateUrl: './envelope-table.component.html',
animations: [
trigger('detailExpand', [
@@ -20,9 +24,7 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
],
styleUrl: './envelope-table.component.scss'
})
export class EnvelopeTableComponent {
@Input() data: Array<any> = []
export class EnvelopeTableComponent implements AfterViewInit {
@Input() options?: { min_status?: number; max_status?: number; ignore_status?: number[] }
@@ -57,13 +59,27 @@ export class EnvelopeTableComponent {
@ViewChild(MatTable) table!: MatTable<any>;
constructor(private erService: EnvelopeReceiverService) { }
@ViewChild(MatPaginator) paginator!: MatPaginator;
async ngOnInit() {
if (this.data.length === 0)
this.data = await this.erService.getEnvelopeReceiverAsync(this.options);
@ViewChild(MatSort) sort!: MatSort;
dataSource = new MatTableDataSource();
constructor(private erService: EnvelopeReceiverService) {
this.dataSource.filterPredicate = (data: any, filter: string): boolean => {
const dataStr = Object.values(data as { [key: string]: any }).reduce((currentTerm, key) => {
return currentTerm + (key ? key.toString().toLowerCase() : '');
}, '').trim().toLowerCase();
return dataStr.indexOf(filter) !== -1;
};
}
async ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
this.dataSource.data = await this.erService.getEnvelopeReceiverAsync(this.options);
this.dataSource.sort = this.sort;
}
public updateTable() {
this.table.renderRows();
}
@@ -71,4 +87,13 @@ export class EnvelopeTableComponent {
isExpandedRow(index: number, row: any): boolean {
return (row?.envelopeId === this.expandedElement?.envelopeId) && (row?.receiverId === this.expandedElement?.receiverId);
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
}

View File

@@ -37,19 +37,19 @@ export class ReceiverInputComponent implements OnInit, OnChanges {
private setupFiltering(): void {
this.filteredOptions = this.control.valueChanges.pipe(
startWith(''),
map(value => this.filter(value || '', this.options)),
map(value => this.filter(value || '', this.options, this.index)),
);
}
control = new FormControl('');
filteredOptions!: Observable<string[]>;
@Input() options: string[] = [];
@Input() filter: (value: string, options: string[]) => string[] = value => {
@Input() filter: (value: string, options: string[], index?: number) => string[] = value => {
const filterValue = value.toLowerCase();
return this.options.filter(option => option.toLowerCase().includes(filterValue));
}
@Input() index?: number;
public get text(): string {
return this.control.value || '';

View File

@@ -1,8 +1,8 @@
<table mat-table [dataSource]="receiverData" class="mat-elevation-z8">
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef> Email </th>
<td mat-cell *matCellDef="let element">
<receiver-input [options]="receiver_mails" [filter]="receiver_filter"></receiver-input>
<td mat-cell *matCellDef="let element; let i = index">
<receiver-input [options]="receiver_mails" [filter]="receiver_filter" [index]="i"></receiver-input>
</td>
</ng-container>

View File

@@ -34,24 +34,39 @@ export class ReceiverTableComponent implements OnInit {
constructor(private receiverService: ReceiverService) { }
async ngOnInit() {
this.receiver_mails = await this.receiverService.getReceiverAsync().then((receivers: any[]) => receivers.map(r => r.emailAddress));
const receivers = await this.receiverService.getReceiverAsync();
this.receiver_mails = receivers.map((r: any) => r.emailAddress);
this.last_used_name = receivers.reduce((acc: any, r: any) => {
acc[r.emailAddress] = r.lastUsedName;
return acc;
}, {} as { [key: string]: string | null });
}
receiver_filter: (value: string, options: string[]) => string[] = (value, options) => {
receiver_filter: (value: string, options: string[], index?: number) => string[] = (value, options, index) => {
const filterValue = value.toLowerCase();
// set the name if it is used befor
const name = this.last_used_name[value];
if (name && index)
this.receiverData.at(index)!.name = name
// !!! do not allow email duplication !!!
var similarMails = this.receiver_mails.filter(m => m.toLocaleLowerCase() === value.toLocaleLowerCase() && m !== value)
if (similarMails.length > 0 && index != undefined) {
this.receiverInputs[index].text = similarMails[0];
}
console.log(this.receiverInputs.length + " - " + index)
// if added into last row
if (value.length > 0 && (this.receiverInputs.at(-1)?.lenght ?? 0) > 0) {
this.receiverData.at(-1)!.accessCode = generateAccessCode();
this.receiverData.push({ email: "", name: "", accessCode: "" });
this.update();
}
else if (value.length == 0) {
for (var i = 0; i < this.receiverInputs.length - 1; i++) {
if (this.receiverInputs[i].lenght === 0) {
this.receiverData.splice(i, 1);
this.update();
}
// delete the row with out mail
else if (value.length === 0 && this.receiverInputs.length - 1 !== index) {
if ( this.receiverInputs.length > 1 && this.receiverInputs[index!]?.lenght === 0) {
this.receiverData.splice(index!, 1);
this.update();
}
}
@@ -59,6 +74,7 @@ export class ReceiverTableComponent implements OnInit {
}
receiver_mails: string[] = [];
last_used_name: { [key: string]: string | null } = {};
@ViewChildren(ReceiverInputComponent) receiverInputsQueryList!: QueryList<ReceiverInputComponent>;
get receiverInputs(): ReceiverInputComponent[] {

View File

@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.GeneratorAPI.Controllers
{
[Route("api/[controller]")]
[Authorize]
[ApiController]
public class EnvelopeReceiverController : ControllerBase
{
@@ -17,8 +18,7 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
_logger = logger;
_erService = envelopeReceiverService;
}
[Authorize]
[HttpGet]
public async Task<IActionResult> GetEnvelopeReceiver([FromQuery] int? min_status = null, [FromQuery] int? max_status = null, [FromQuery] int[]? ignore_status = null)
{
@@ -49,5 +49,28 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("receiver-name/{mail}")]
public async Task<IActionResult> GetReceiverName([FromRoute] string mail)
{
try
{
return await _erService.ReadLastUsedReceiverNameByMail(mail).ThenAsync(
Success: res => res is null ? Ok(string.Empty) : Ok(res),
Fail: IActionResult (msg, ntc) =>
{
if (ntc.HasFlag(Flag.NotFound))
return NotFound();
_logger.LogNotice(ntc);
return StatusCode(StatusCodes.Status500InternalServerError);
});
}
catch(Exception ex)
{
_logger.LogError(ex, "{message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
}

View File

@@ -20,5 +20,7 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
Task<string?> ReadAccessCodeByIdAsync(int envelopeId, int receiverId);
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
Task<EnvelopeReceiver?> ReadLastByReceiver(string email);
}
}

View File

@@ -1,5 +1,4 @@
using DigitalData.Core.Infrastructure;
using DigitalData.UserManager.Infrastructure.Repositories;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.EntityFrameworkCore;
@@ -76,5 +75,10 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
return await query.Include(er => er.Envelope).Include(er => er.Receiver).ToListAsync();
}
public async Task<EnvelopeReceiver?> ReadLastByReceiver(string email)
{
return await _dbSet.Where(er => er.Receiver!.EmailAddress == email).OrderBy(er => er.EnvelopeId).LastOrDefaultAsync();
}
}
}

View File

@@ -11,7 +11,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
{
}
protected IQueryable<Receiver> ReadBy(string? emailAddress = null, string? signature = null)
protected IQueryable<Receiver> ReadBy(string? emailAddress = null, string? signature = null, bool withLastUsedName = true)
{
IQueryable<Receiver> query = _dbSet.AsNoTracking();
@@ -21,9 +21,17 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
if(signature is not null)
query = query.Where(r => r.Signature == signature);
// envelope receivers are ignored (with '[JsonIgnore]' attribute). The reson to add them is to get the las used receiver name
if (withLastUsedName)
{
query = query.Include(r => r.EnvelopeReceivers!.OrderByDescending(er => er.EnvelopeId).Take(1));
}
return query;
}
public async Task<Receiver?> ReadByAsync(string? emailAddress = null, string? signature = null) => await ReadBy(emailAddress, signature).FirstOrDefaultAsync();
public async override Task<IEnumerable<Receiver>> ReadAllAsync() => await ReadBy().ToListAsync();
}
}

View File

@@ -10,11 +10,11 @@ using DigitalData.Core.API;
using EnvelopeGenerator.Application;
using Microsoft.Extensions.Localization;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs;
using Microsoft.AspNetCore.Localization;
using System.Text.Encodings.Web;
using EnvelopeGenerator.Web.Models;
using EnvelopeGenerator.Application.Resources;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
namespace EnvelopeGenerator.Web.Controllers
{

View File

@@ -1,12 +1,12 @@
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using Microsoft.AspNetCore.Mvc;
using System.Net;
namespace EnvelopeGenerator.Web.Controllers.Test
{
[ApiController]
[ApiController]
[Route("api/test/[controller]")]
public class TestEnvelopeMailController : ControllerBase
{

View File

@@ -1,10 +1,10 @@
using DigitalData.Core.API;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application;
using EnvelopeGenerator.Domain.Entities;
using Microsoft.AspNetCore.Mvc;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
namespace EnvelopeGenerator.Web.Controllers.Test
{

View File

@@ -4,10 +4,10 @@
@{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
}
@using DigitalData.Core.DTO;
@using EnvelopeGenerator.Application.DTOs;
@using Newtonsoft.Json
@using Newtonsoft.Json.Serialization
@ using DigitalData.Core.DTO;
@ using EnvelopeGenerator.Application.DTOs;
@ using Newtonsoft.Json
@ using Newtonsoft.Json.Serialization
@model EnvelopeReceiverDto;
<partial name="_CookieConsentPartial" />
@{

View File

@@ -1,10 +1,10 @@
@{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
}
@using DigitalData.Core.DTO;
@using EnvelopeGenerator.Application.DTOs;
@using Newtonsoft.Json
@using Newtonsoft.Json.Serialization
@ using DigitalData.Core.DTO;
@ using EnvelopeGenerator.Application.DTOs;
@ using Newtonsoft.Json
@ using Newtonsoft.Json.Serialization
@model EnvelopeReceiverDto;
@{
ViewData["Title"] = _localizer[WebKey.SignDoc];