Compare commits

...

4 Commits

22 changed files with 277 additions and 79 deletions

View File

@@ -2,11 +2,10 @@
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
namespace EnvelopeGenerator.Application.Contracts
{
public interface IEnvelopeReceiverService : IBasicCRUDService<EnvelopeReceiverDto, EnvelopeReceiver, int>
public interface IEnvelopeReceiverService : IBasicCRUDService<EnvelopeReceiverDto, EnvelopeReceiver, object>
{
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false);
@@ -24,5 +23,7 @@ namespace EnvelopeGenerator.Application.Contracts
Task<DataResult<bool>> VerifyAccessCodeAsync(string envelopeReceiverId, string accessCode);
Task<DataResult<bool>> IsExisting(string envelopeReceiverId);
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username);
}
}

View File

@@ -0,0 +1,57 @@
using DigitalData.UserManager.Application.MappingProfiles;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.MappingProfiles;
using EnvelopeGenerator.Application.Services;
using EnvelopeGenerator.Infrastructure.Contracts;
using EnvelopeGenerator.Infrastructure.Repositories;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnvelopeGenerator.Application
{
public static class DIExtensions
{
public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services)
{
//Inject CRUD Service and repositoriesad
services.AddScoped<IConfigRepository, ConfigRepository>();
services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
services.AddScoped<IConfigRepository, ConfigRepository>();
services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
services.AddScoped<IDocumentStatusRepository, DocumentStatusRepository>();
services.AddScoped<IEmailTemplateRepository, EmailTemplateRepository>();
services.AddScoped<IEnvelopeRepository, EnvelopeRepository>();
services.AddScoped<IEnvelopeCertificateRepository, EnvelopeCertificateRepository>();
services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
services.AddScoped<IEnvelopeHistoryRepository, EnvelopeHistoryRepository>();
services.AddScoped<IEnvelopeReceiverRepository, EnvelopeReceiverRepository>();
services.AddScoped<IEnvelopeTypeRepository, EnvelopeTypeRepository>();
services.AddScoped<IReceiverRepository, ReceiverRepository>();
services.AddScoped<IUserReceiverRepository, UserReceiverRepository>();
services.AddScoped<IConfigService, ConfigService>();
services.AddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>();
services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
services.AddScoped<IEnvelopeHistoryService, EnvelopeHistoryService>();
services.AddScoped<IDocumentStatusService, DocumentStatusService>();
services.AddScoped<IEmailTemplateService, EmailTemplateService>();
services.AddScoped<IEnvelopeService, EnvelopeService>();
services.AddScoped<IEnvelopeCertificateService, EnvelopeCertificateService>();
services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
services.AddScoped<IEnvelopeReceiverService, EnvelopeReceiverService>();
services.AddScoped<IEnvelopeTypeService, EnvelopeTypeService>();
services.AddScoped<IReceiverService, ReceiverService>();
services.AddScoped<IUserReceiverService, UserReceiverService>();
//Auto mapping profiles
services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
services.AddAutoMapper(typeof(UserMappingProfile).Assembly);
return services;
}
}
}

View File

@@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging;
namespace EnvelopeGenerator.Application.Services
{
public class EnvelopeReceiverService : BasicCRUDService<IEnvelopeReceiverRepository, EnvelopeReceiverDto, EnvelopeReceiver, int>, IEnvelopeReceiverService
public class EnvelopeReceiverService : BasicCRUDService<IEnvelopeReceiverRepository, EnvelopeReceiverDto, EnvelopeReceiver, object>, IEnvelopeReceiverService
{
private readonly IStringLocalizer<Resource> _localizer;
@@ -115,5 +115,12 @@ namespace EnvelopeGenerator.Application.Services
Result.Fail<string>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"Access code is null. Envelope ID is {envelopeId} and receiver ID {receiverId}")
: Result.Success(code);
}
}
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username)
{
var er_list = await _repository.ReadByUsernameAsync(username: username);
var dto_list = _mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(er_list);
return Result.Success(dto_list);
}
}
}

View File

@@ -11,9 +11,6 @@
</ItemGroup>
<ItemGroup>
<Reference Include="DigitalData.Core.Domain">
<HintPath>..\..\WebCoreModules\DigitalData.Core.Domain\bin\Debug\net7.0\DigitalData.Core.Domain.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Domain">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Domain\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath>
</Reference>

View File

@@ -74,7 +74,10 @@
"buildTarget": "envelope-generator-ui:build:development"
}
},
"defaultConfiguration": "development"
"defaultConfiguration": "development",
"options": {
"proxyConfig": "src/proxy.conf.json"
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",

View File

@@ -1,5 +1,4 @@
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './components/login/login.component';
import {EnvelopeTableComponent} from '../app/components/envelope-table/envelope-table.component'
import {HomeComponent} from '../app/components/home/home.component'
export const routes: Routes = [

View File

@@ -1,4 +1,6 @@
import { Component } from '@angular/core';
import { EnvelopeReceiverService } from '../../services/envelope-receiver.service';
import { error } from 'console';
@Component({
selector: 'app-envelope-table',
@@ -8,5 +10,15 @@ import { Component } from '@angular/core';
styleUrl: './envelope-table.component.scss'
})
export class EnvelopeTableComponent {
constructor(private erService : EnvelopeReceiverService){
erService.getEnvelopeReceiver().subscribe({
next: (res) => {
console.log(res)
},
error: (error) => {
console.log(error)
}
});
}
}

View File

@@ -35,10 +35,9 @@ export class LoginComponent {
if (this.loginForm.valid) {
this.authService.login(this.loginForm.value).subscribe({
next: () => {
this.router.navigate(['/envelope']); // Adjust to your protected route
this.router.navigate(['/envelope']);
},
error: error => {
// Handle login error
console.error('Login failed', error);
}
});

View File

@@ -2,7 +2,7 @@ import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { API_URL } from '../tokens/index';
import { HttpClientModule } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { EnvelopeReceiverService } from './envelope-receiver.service';
describe('EnvelopeReceiverService', () => {
let service: EnvelopeReceiverService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(EnvelopeReceiverService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,24 @@
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, catchError } from 'rxjs';
import { API_URL } from '../tokens/index';
@Injectable({
providedIn: 'root'
})
export class EnvelopeReceiverService {
private url: string;
constructor(private http: HttpClient) {
const api_url = inject(API_URL);
this.url = `${api_url}/envelopereceiver`;
}
getEnvelopeReceiver(): Observable<any> {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
});
return this.http.get<any>(this.url, { withCredentials: true , headers });
}
}

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8">
<title>signFlow</title>
<base href="/">
<meta name="api-url" content="https://localhost:7174/api">
<meta name="api-url" content="/api">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">

View File

@@ -0,0 +1,7 @@
{
"/api": {
"target": "https://localhost:7174",
"secure": false,
"changeOrigin": true
}
}

View File

@@ -31,6 +31,7 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
}
//TODO: When a user group is created for signFlow, add a process to check if the user is in this group (like "PM_USER")
[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LogInDto login)
{
@@ -39,26 +40,26 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
bool isValid = _dirSearchService.ValidateCredentials(login.Username, login.Password);
if (!isValid)
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound]));
return Unauthorized();
//find the user
var uRes = await _userService.ReadByUsernameAsync(login.Username);
if (!uRes.IsSuccess || uRes.Data is null)
{
return Unauthorized(uRes);
return Forbid();
}
UserReadDto user = uRes.Data;
// Create claims
var claims = new List<Claim>
{
new (ClaimTypes.NameIdentifier, user.Guid.ToString()),
new (ClaimTypes.Name, user.Username),
new (ClaimTypes.Surname, user.Name!),
new (ClaimTypes.GivenName, user.Prename!),
new (ClaimTypes.Email, user.Email!),
};
{
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
new (ClaimTypes.Name, user.Username),
new (ClaimTypes.Surname, user.Name!),
new (ClaimTypes.GivenName, user.Prename!),
new (ClaimTypes.Email, user.Email!),
};
// Create claimsIdentity
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

View File

@@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace EnvelopeGenerator.GeneratorAPI.Controllers
{
public static class ControllerExtensions
{
public static int? GetId(this ControllerBase controller)
=> int.TryParse(controller.User.FindFirst(ClaimTypes.NameIdentifier)?.Value, out int result)
? result : null;
public static string? GetUsername(this ControllerBase controller)
=> controller.User.FindFirst(ClaimTypes.Name)?.Value;
public static string? GetName(this ControllerBase controller)
=> controller.User.FindFirst(ClaimTypes.Surname)?.Value;
public static string? GetPrename(this ControllerBase controller)
=> controller.User.FindFirst(ClaimTypes.GivenName)?.Value;
public static string? GetEmail(this ControllerBase controller)
=> controller.User.FindFirst(ClaimTypes.Email)?.Value;
}
}

View File

@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Http;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.Contracts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.GeneratorAPI.Controllers
@@ -7,5 +9,43 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
[ApiController]
public class EnvelopeReceiverController : ControllerBase
{
private readonly ILogger<EnvelopeReceiverController> _logger;
private readonly IEnvelopeReceiverService _erService;
public EnvelopeReceiverController(ILogger<EnvelopeReceiverController> logger, IEnvelopeReceiverService envelopeReceiverService)
{
_logger = logger;
_erService = envelopeReceiverService;
}
[Authorize]
[HttpGet]
public async Task<IActionResult> GetEnvelopeReceiver()
{
try
{
var username = this.GetUsername();
if (username is null)
{
_logger.LogError(@"Envelope Receiver dto cannot be sent because username claim is null. Potential authentication and authorization error. The value of other claims are [id: {id}], [username: {username}], [name: {name}], [prename: {prename}], [email: {email}].",
this.GetId(), this.GetUsername(), this.GetName(), this.GetPrename(), this.GetEmail());
return StatusCode(StatusCodes.Status500InternalServerError);
}
return await _erService.ReadByUsernameAsync(username).ThenAsync(
Success: Ok,
Fail: IActionResult (msg, ntc) =>
{
_logger.LogNotice(ntc);
return StatusCode(StatusCodes.Status500InternalServerError, msg);
});
}
catch(Exception ex)
{
_logger.LogError(ex, "An unexpected error occurred. {message}", ex.Message);
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
}
}

View File

@@ -45,4 +45,31 @@
</Reference>
</ItemGroup>
<ItemGroup>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\chunk-35PBLQEP.js">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\chunk-IUSOII6E.js">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\favicon.ico">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\index.html">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\login\index.html">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\main-ZN7C4PGY.js">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\polyfills-N6LQB2YD.js">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\styles-S5ZWIC2V.css">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -2,6 +2,7 @@ using DigitalData.Core.API;
using DigitalData.Core.Application;
using DigitalData.UserManager.Application;
using DigitalData.UserManager.Infrastructure.Repositories;
using EnvelopeGenerator.Application;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;
@@ -35,7 +36,16 @@ var connStr = config.GetConnectionString("Default") ?? throw new InvalidOperatio
builder.Services.AddDbContext<EGDbContext>(options => options.UseSqlServer(connStr));
// Authentication
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
if (builder.Environment.IsDevelopment())
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.HttpOnly = true;
options.LoginPath = "/api/auth/login";
options.LogoutPath = "/api/auth/logout";
});
else
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security
@@ -55,6 +65,9 @@ builder.Services.AddDirectorySearchService();
// Localizer
builder.Services.AddCookieBasedLocalizer() ;
// Envelope generator serives
builder.Services.AddEnvelopeGenerator();
var app = builder.Build();
// Configure the HTTP request pipeline.
@@ -75,8 +88,8 @@ app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

View File

@@ -3,7 +3,7 @@ using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Infrastructure.Contracts
{
public interface IEnvelopeReceiverRepository : ICRUDRepository<EnvelopeReceiver, int>
public interface IEnvelopeReceiverRepository : ICRUDRepository<EnvelopeReceiver, object>
{
Task<IEnumerable<EnvelopeReceiver>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false);
@@ -18,5 +18,7 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
Task<EnvelopeReceiver?> ReadByIdAsync(int envelopeId, int receiverId);
Task<string?> ReadAccessCodeByIdAsync(int envelopeId, int receiverId);
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username);
}
}

View File

@@ -3,11 +3,10 @@ using DigitalData.UserManager.Infrastructure.Repositories;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.EntityFrameworkCore;
using System;
namespace EnvelopeGenerator.Infrastructure.Repositories
{
public class EnvelopeReceiverRepository : CRUDRepository<EnvelopeReceiver, int, EGDbContext>, IEnvelopeReceiverRepository
public class EnvelopeReceiverRepository : CRUDRepository<EnvelopeReceiver, object, EGDbContext>, IEnvelopeReceiverRepository
{
public EnvelopeReceiverRepository(EGDbContext dbContext) : base(dbContext)
{
@@ -15,9 +14,9 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
private IQueryable<EnvelopeReceiver> ReadWhere(string? uuid = null, string? signature = null, bool withEnvelope = false, bool withReceiver = false)
{
var query = _dbSet.AsQueryable();
var query = _dbSet.AsNoTracking();
if(uuid is not null)
if (uuid is not null)
query = query.Where(er => er.Envelope != null && er.Envelope.Uuid == uuid);
if (signature is not null)
@@ -37,29 +36,36 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
public async Task<IEnumerable<EnvelopeReceiver>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false)
=> await ReadWhere(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver).ToListAsync();
public async Task<IEnumerable<EnvelopeReceiver>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true)
public async Task<IEnumerable<EnvelopeReceiver>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true)
=> await ReadWhere(signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver).ToListAsync();
public async Task<EnvelopeReceiver?> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true)
public async Task<EnvelopeReceiver?> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true)
=> await ReadWhere(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver).FirstOrDefaultAsync();
public async Task<string?> ReadAccessCodeAsync(string uuid, string signature)
=> await ReadWhere(uuid:uuid, signature:signature)
public async Task<string?> ReadAccessCodeAsync(string uuid, string signature)
=> await ReadWhere(uuid: uuid, signature: signature)
.Select(er => er.AccessCode)
.FirstOrDefaultAsync();
public async Task<int> CountAsync(string uuid, string signature) => await ReadWhere(uuid: uuid, signature: signature).CountAsync();
public IQueryable<EnvelopeReceiver> ReadById(int envelopeId, int receiverId) => _dbSet
public IQueryable<EnvelopeReceiver> ReadById(int envelopeId, int receiverId) => _dbSet
.Where(er => er.EnvelopeId == envelopeId && er.ReceiverId == receiverId);
public async Task<EnvelopeReceiver?> ReadByIdAsync(int envelopeId, int receiverId)
public async Task<EnvelopeReceiver?> ReadByIdAsync(int envelopeId, int receiverId)
=> await ReadById(envelopeId: envelopeId, receiverId: receiverId)
.FirstOrDefaultAsync();
public async Task<string?> ReadAccessCodeByIdAsync(int envelopeId, int receiverId)
=> await ReadById(envelopeId: envelopeId, receiverId: receiverId)
.Select(er => er.AccessCode)
.FirstOrDefaultAsync();
}
.FirstOrDefaultAsync();
public async Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username) => await _dbSet
.AsNoTracking()
.Where(er => er.Envelope!.User!.Username == username)
.Include(er => er.Envelope)
.Include(er => er.Receiver)
.ToListAsync();
}
}

View File

@@ -4,12 +4,11 @@ using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Web.Controllers.Test
{
public class TestEnvelopeReceiverController : TestControllerBase<IEnvelopeReceiverService, EnvelopeReceiverDto, EnvelopeReceiver, int>
public class TestEnvelopeReceiverController : TestControllerBase<IEnvelopeReceiverService, EnvelopeReceiverDto, EnvelopeReceiver, object>
{
public TestEnvelopeReceiverController(ILogger<TestEnvelopeReceiverController> logger, IEnvelopeReceiverService service) : base(logger, service)
{

View File

@@ -1,9 +1,6 @@
using DigitalData.UserManager.Infrastructure.Repositories;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.MappingProfiles;
using EnvelopeGenerator.Application.Services;
using EnvelopeGenerator.Infrastructure.Contracts;
using EnvelopeGenerator.Infrastructure.Repositories;
using EnvelopeGenerator.Web.Services;
using Microsoft.EntityFrameworkCore;
using NLog;
@@ -11,7 +8,6 @@ using Quartz;
using NLog.Web;
using DigitalData.Core.API;
using Microsoft.AspNetCore.Authentication.Cookies;
using DigitalData.UserManager.Application.MappingProfiles;
using EnvelopeGenerator.Web.Models;
using DigitalData.Core.DTO;
using System.Text.Encodings.Web;
@@ -19,7 +15,6 @@ using Ganss.Xss;
using Microsoft.Extensions.Options;
using DigitalData.EmailProfilerDispatcher.Application;
using EnvelopeGenerator.Application;
using EnvelopeGenerator.Application.Resources;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Info("Logging initialized!");
@@ -76,39 +71,8 @@ try
var connStr = config.GetConnectionString(Key.Default) ?? throw new InvalidOperationException("There is no default connection string in appsettings.json.");
builder.Services.AddDbContext<EGDbContext>(options => options.UseSqlServer(connStr));
//Inject CRUD Service and repositoriesad
builder.Services.AddScoped<IConfigRepository, ConfigRepository>();
builder.Services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
builder.Services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
builder.Services.AddScoped<IConfigRepository, ConfigRepository>();
builder.Services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
builder.Services.AddScoped<IDocumentStatusRepository, DocumentStatusRepository>();
builder.Services.AddScoped<IEmailTemplateRepository, EmailTemplateRepository>();
builder.Services.AddScoped<IEnvelopeRepository, EnvelopeRepository>();
builder.Services.AddScoped<IEnvelopeCertificateRepository, EnvelopeCertificateRepository>();
builder.Services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
builder.Services.AddScoped<IEnvelopeHistoryRepository, EnvelopeHistoryRepository>();
builder.Services.AddScoped<IEnvelopeReceiverRepository, EnvelopeReceiverRepository>();
builder.Services.AddScoped<IEnvelopeTypeRepository, EnvelopeTypeRepository>();
builder.Services.AddScoped<IReceiverRepository, ReceiverRepository>();
builder.Services.AddScoped<IUserReceiverRepository, UserReceiverRepository>();
builder.Services.AddScoped<IConfigService, ConfigService>();
builder.Services.AddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>();
builder.Services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
builder.Services.AddScoped<IEnvelopeHistoryService, EnvelopeHistoryService>();
builder.Services.AddScoped<IDocumentStatusService, DocumentStatusService>();
builder.Services.AddScoped<IEmailTemplateService, EmailTemplateService>();
builder.Services.AddScoped<IEnvelopeService, EnvelopeService>();
builder.Services.AddScoped<IEnvelopeCertificateService, EnvelopeCertificateService>();
builder.Services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
builder.Services.AddScoped<IEnvelopeReceiverService, EnvelopeReceiverService>();
builder.Services.AddScoped<IEnvelopeTypeService, EnvelopeTypeService>();
builder.Services.AddScoped<IReceiverService, ReceiverService>();
builder.Services.AddScoped<IUserReceiverService, UserReceiverService>();
//Auto mapping profiles
builder.Services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
builder.Services.AddAutoMapper(typeof(UserMappingProfile).Assembly);
// Add envelope generator services
builder.Services.AddEnvelopeGenerator();
builder.Services.Configure<CookiePolicyOptions>(options =>
{