Compare commits

...

5 Commits

Author SHA1 Message Date
2d7d23d26b
update ci pipeline to reflect Identity project removeal
All checks were successful
/ build (push) Successful in 6m7s
/ tests (push) Successful in 27s
/ build-docker (push) Successful in 5m11s
2025-05-28 12:35:04 +03:00
fafb665cd2
rewrite identity system 2025-05-28 12:33:49 +03:00
4ae17c5a91
add vehicle enrollment employee management 2025-05-27 18:10:53 +03:00
57264b384c
add vehicle and company info to vehicle enrollment search dto 2025-05-27 14:08:40 +03:00
a97b95a704
remove unnecessary todos 2025-05-27 12:58:14 +03:00
359 changed files with 5965 additions and 3527 deletions

View File

@ -25,7 +25,6 @@ jobs:
cache: true
cache-dependency-path: |
src/Application/packages.lock.json
src/Identity/packages.lock.json
src/Infrastructure/packages.lock.json
src/Persistence/packages.lock.json
src/Configuration/packages.lock.json

View File

@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "src\Infra
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpApi", "src\HttpApi\HttpApi.csproj", "{4431B3CB-A5F2-447A-8BC7-9DC3DA9E6A6D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity", "src\Identity\Identity.csproj", "{AD3CC01F-0331-44DC-B58E-CCE6ADCB56B6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Configuration", "src\Configuration\Configuration.csproj", "{1DCFA4EE-A545-42FE-A3BC-A606D2961298}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application.IntegrationTests", "tst\Application.IntegrationTests\Application.IntegrationTests.csproj", "{B52B8651-10B8-488D-8ACF-9C4499F8A723}"
@ -48,10 +46,6 @@ Global
{4431B3CB-A5F2-447A-8BC7-9DC3DA9E6A6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4431B3CB-A5F2-447A-8BC7-9DC3DA9E6A6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4431B3CB-A5F2-447A-8BC7-9DC3DA9E6A6D}.Release|Any CPU.Build.0 = Release|Any CPU
{AD3CC01F-0331-44DC-B58E-CCE6ADCB56B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD3CC01F-0331-44DC-B58E-CCE6ADCB56B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD3CC01F-0331-44DC-B58E-CCE6ADCB56B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD3CC01F-0331-44DC-B58E-CCE6ADCB56B6}.Release|Any CPU.Build.0 = Release|Any CPU
{1DCFA4EE-A545-42FE-A3BC-A606D2961298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DCFA4EE-A545-42FE-A3BC-A606D2961298}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DCFA4EE-A545-42FE-A3BC-A606D2961298}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.AddAddress;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Domain.Entities;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.DeleteAddress;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.DeleteAddress;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Commands.UpdateAddress;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddress;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using AutoMapper;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Addresses.Queries.GetAddressesPage;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Extensions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.AddAircraft;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Domain.Entities;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.DeleteAircraft;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.DeleteAircraft;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.UpdateAircraft;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraft;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using AutoMapper;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraftsPage;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Extensions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -16,7 +16,10 @@
<PackageReference Include="FluentValidation" Version="11.11.0" />
<PackageReference Include="MediatR" Version="12.4.1" />
<PackageReference Include="MediatR.Behaviors.Authorization" Version="12.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.4" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.11.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.11.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="QuikGraph" Version="2.5.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.2" />

View File

@ -4,6 +4,8 @@ namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.Register;
public record RegisterCommand : IRequest
{
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }

View File

@ -0,0 +1,13 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.Register;
public class RegisterCommandAuthorizer :
AbstractRequestAuthorizer<RegisterCommand>
{
public override void BuildPolicy(RegisterCommand request)
{
UseRequirement(new AllowAllRequirement());
}
}

View File

@ -1,21 +1,83 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using System.Security.Cryptography;
using System.Text;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Entities;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.Register;
public class RegisterCommandHandler : IRequestHandler<RegisterCommand>
{
private readonly AuthenticationService _authenticationService;
private readonly IReadOnlyCollection<IdentityRole> DefaultRoles =
new IdentityRole[] { IdentityRole.User };
public RegisterCommandHandler(AuthenticationService authenticationService)
private readonly UnitOfWork _unitOfWork;
private readonly PasswordHasherService _passwordHasher;
public RegisterCommandHandler(UnitOfWork unitOfWork,
PasswordHasherService passwordHasher)
{
_authenticationService = authenticationService;
_unitOfWork = unitOfWork;
_passwordHasher = passwordHasher;
}
public async Task Handle(
RegisterCommand request, CancellationToken cancellationToken)
public async Task Handle(RegisterCommand request,
CancellationToken cancellationToken)
{
await _authenticationService.RegisterAsync(
request.Email, request.Password, cancellationToken);
var datastoreAccount = await _unitOfWork.AccountRepository
.GetOneAsync(
e =>
e.Email == request.Email ||
e.Username == request.Username,
cancellationToken);
if (datastoreAccount != null)
{
throw new RegistrationException(
"User with given email or username already registered.");
}
var defaultRoleIds = (await _unitOfWork.RoleRepository
.GetPageAsync(
r => DefaultRoles.Contains(r.Value),
1, DefaultRoles.Count, cancellationToken))
.Items
.Select(r => r.Id);
var password = Encoding.UTF8.GetBytes(request.Password);
var salt = RandomNumberGenerator.GetBytes(128 / 8);
var hash = await _passwordHasher
.HashAsync(password, salt, cancellationToken);
var saltBase64 = Convert.ToBase64String(salt);
var hashBase64 = Convert.ToBase64String(hash);
var newAccount = new Account
{
Username = request.Username,
Email = request.Email,
PasswordHash = hashBase64,
PasswordSalt = saltBase64,
AccountRoles = defaultRoleIds.Select(id =>
new AccountRole()
{
RoleId = id
})
.ToArray()
};
await _unitOfWork.AccountRepository
.AddOneAsync(newAccount, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
_unitOfWork.Dispose();
}
}

View File

@ -1,31 +1,54 @@
using cuqmbr.TravelGuide.Application.Common.FluentValidation;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.Register;
public class RegisterCommandValidator : AbstractValidator<RegisterCommand>
{
public RegisterCommandValidator()
public RegisterCommandValidator(
IStringLocalizer localizer,
SessionCultureService cultureService)
{
RuleFor(v => v.Username)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"])
.MinimumLength(1)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.MinimumLength"],
1))
.MaximumLength(32)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.MaximumLength"],
32))
.IsUsername()
.WithMessage(localizer["FluentValidation.IsUsername"]);
RuleFor(v => v.Email)
.NotEmpty()
.WithMessage("Email address is required.")
.Matches(@"\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b")
.WithMessage("Email address is invalid.");
.WithMessage(localizer["FluentValidation.NotEmpty"])
.IsEmail()
.WithMessage(localizer["FluentValidation.IsEmail"]);
RuleFor(v => v.Password)
.NotEmpty()
.WithMessage("Password is required.")
.WithMessage(localizer["FluentValidation.NotEmpty"])
.MinimumLength(8)
.WithMessage("Password must be at least 8 characters long.")
.MaximumLength(64)
.WithMessage("Password must be at most 64 characters long.")
.Matches(@"(?=.*[A-Z]).*")
.WithMessage("Password must contain at least one uppercase letter.")
.Matches(@"(?=.*[a-z]).*")
.WithMessage("Password must contain at least one lowercase letter.")
.Matches(@"(?=.*[\d]).*")
.WithMessage("Password must contain at least one digit.")
.Matches(@"(?=.*[!@#$%^&*()]).*")
.WithMessage("Password must contain at least one of the following special charactters: !@#$%^&*().");
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.MinimumLength"],
8))
.MaximumLength(256)
.WithMessage(
String.Format(
cultureService.Culture,
localizer["FluentValidation.MaximumLength"],
256));
}
}

View File

@ -1,5 +1,5 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
// using cuqmbr.TravelGuide.Application.Common.Services;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.RenewAccessToken;
@ -7,18 +7,19 @@ namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.RenewAccessToken
public class RenewAccessTokenCommandAuthorizer :
AbstractRequestAuthorizer<RenewAccessTokenCommand>
{
private readonly SessionUserService _sessionUserService;
public RenewAccessTokenCommandAuthorizer(SessionUserService currentUserService)
{
_sessionUserService = currentUserService;
}
// private readonly SessionUserService _sessionUserService;
//
// public RenewAccessTokenCommandAuthorizer(SessionUserService currentUserService)
// {
// _sessionUserService = currentUserService;
// }
public override void BuildPolicy(RenewAccessTokenCommand request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated = _sessionUserService.IsAuthenticated
});
UseRequirement(new AllowAllRequirement());
// UseRequirement(new MustBeAuthenticatedRequirement
// {
// IsAuthenticated = _sessionUserService.IsAuthenticated
// });
}
}

View File

@ -1,22 +1,95 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Domain.Entities;
using MediatR;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.RenewAccessToken;
public class RenewAccessTokenCommandHandler :
IRequestHandler<RenewAccessTokenCommand, TokensModel>
{
private readonly AuthenticationService _authenticationService;
private readonly UnitOfWork _unitOfWork;
private readonly JsonWebTokenConfigurationOptions _jwtConfiguration;
public RenewAccessTokenCommandHandler(AuthenticationService authenticationService)
public RenewAccessTokenCommandHandler(UnitOfWork unitOfWork,
IOptions<ConfigurationOptions> configurationOptions)
{
_authenticationService = authenticationService;
_unitOfWork = unitOfWork;
_jwtConfiguration = configurationOptions.Value.JsonWebToken;
}
public async Task<TokensModel> Handle(
RenewAccessTokenCommand request, CancellationToken cancellationToken)
{
return await _authenticationService.RenewAccessTokenAsync(
request.RefreshToken, cancellationToken);
var refreshToken = (await _unitOfWork.RefreshTokenRepository
.GetOneAsync(e => e.Value == request.RefreshToken,
cancellationToken));
if (refreshToken == null)
{
throw new AuthenticationException($"Refresh token was not found.");
}
if (!refreshToken.IsActive)
{
throw new AuthenticationException("Refresh token is inactive.");
}
var account = await _unitOfWork.AccountRepository.GetOneAsync(
a => a.RefreshTokens.Contains(refreshToken),
a => a.AccountRoles, cancellationToken);
var jwtSecurityToken = await CreateJwtAsync(account, cancellationToken);
var accessToken = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
return new TokensModel(accessToken, refreshToken.Value);
}
private async Task<JwtSecurityToken> CreateJwtAsync(
Account account, CancellationToken cancellationToken)
{
var roleIds = account.AccountRoles.Select(ar => ar.RoleId);
var roles = (await _unitOfWork.RoleRepository
.GetPageAsync(
r => roleIds.Contains(r.Id),
1, roleIds.Count(), cancellationToken))
.Items.Select(r => r.Value);
var roleClaims = new List<Claim>();
foreach (var role in roles)
{
roleClaims.Add(new Claim("roles", role.Name));
}
var claims = new List<Claim>()
{
new Claim(JwtRegisteredClaimNames.Sub, account.Guid.ToString()),
new Claim(JwtRegisteredClaimNames.Nickname, account.Username),
new Claim(JwtRegisteredClaimNames.Email, account.Email)
}
.Union(roleClaims);
var expirationDateTimeUtc = DateTime.UtcNow.Add(
_jwtConfiguration.AccessTokenValidity);
var symmetricSecurityKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_jwtConfiguration.IssuerSigningKey));
var signingCredentials = new SigningCredentials(
symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
var jwtSecurityToken = new JwtSecurityToken(
issuer: _jwtConfiguration.Issuer,
audience: _jwtConfiguration.Audience,
claims: claims,
expires: expirationDateTimeUtc,
signingCredentials: signingCredentials);
return jwtSecurityToken;
}
}

View File

@ -1,6 +0,0 @@
using MediatR;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RenewAccessTokenWithCookie;
public record RenewAccessTokenWithCookieCommand : IRequest<TokensModel> { }

View File

@ -1,26 +0,0 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RenewAccessTokenWithCookie;
public class RenewAccessTokenWithCookieCommandAuthorizer :
AbstractRequestAuthorizer<RenewAccessTokenWithCookieCommand>
{
private readonly SessionUserService _sessionUserService;
public RenewAccessTokenWithCookieCommandAuthorizer(
SessionUserService currentUserService)
{
_sessionUserService = currentUserService;
}
public override void BuildPolicy(RenewAccessTokenWithCookieCommand request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated = _sessionUserService.IsAuthenticated
});
}
}

View File

@ -1,28 +0,0 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using MediatR;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RenewAccessTokenWithCookie;
public class RenewAccessTokenWithCookieCommandHandler :
IRequestHandler<RenewAccessTokenWithCookieCommand, TokensModel>
{
private readonly AuthenticationService _authenticationService;
private readonly SessionUserService _sessionUserService;
public RenewAccessTokenWithCookieCommandHandler(
AuthenticationService authenticationService,
SessionUserService sessionUserService)
{
_authenticationService = authenticationService;
_sessionUserService = sessionUserService;
}
public async Task<TokensModel> Handle(
RenewAccessTokenWithCookieCommand request,
CancellationToken cancellationToken)
{
return await _authenticationService.RenewAccessTokenAsync(
_sessionUserService.RefreshToken, cancellationToken);
}
}

View File

@ -1,10 +0,0 @@
using FluentValidation;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RenewAccessTokenWithCookie;
public class RenewAccessTokenWithCookieCommandValidator :
AbstractValidator<RenewAccessTokenWithCookieCommand>
{
public RenewAccessTokenWithCookieCommandValidator() { }
}

View File

@ -1,5 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.RevokeRefreshToken;
@ -7,18 +6,8 @@ namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.RevokeRefreshTok
public class RevokeRefreshTokenCommandAuthorizer :
AbstractRequestAuthorizer<RevokeRefreshTokenCommand>
{
private readonly SessionUserService _sessionUserService;
public RevokeRefreshTokenCommandAuthorizer(SessionUserService currentUserService)
{
_sessionUserService = currentUserService;
}
public override void BuildPolicy(RevokeRefreshTokenCommand request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated = _sessionUserService.IsAuthenticated
});
UseRequirement(new AllowAllRequirement());
}
}

View File

@ -1,4 +1,5 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using MediatR;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.RevokeRefreshToken;
@ -6,17 +7,36 @@ namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands.RevokeRefreshTok
public class RevokeRefreshTokenCommandHandler :
IRequestHandler<RevokeRefreshTokenCommand>
{
private readonly AuthenticationService _authenticationService;
private readonly UnitOfWork _unitOfWork;
public RevokeRefreshTokenCommandHandler(AuthenticationService authenticationService)
public RevokeRefreshTokenCommandHandler(UnitOfWork unitOfWork)
{
_authenticationService = authenticationService;
_unitOfWork = unitOfWork;
}
public async Task Handle(
RevokeRefreshTokenCommand request, CancellationToken cancellationToken)
{
await _authenticationService.RevokeRefreshTokenAsync(
request.RefreshToken, cancellationToken);
var refreshToken = (await _unitOfWork.RefreshTokenRepository
.GetOneAsync(e => e.Value == request.RefreshToken,
cancellationToken));
if (refreshToken == null)
{
throw new AuthenticationException("Invalid refreshToken");
}
if (!refreshToken.IsActive)
{
throw new AuthenticationException("RefreshToken already revoked");
}
refreshToken.RevocationTime = DateTimeOffset.UtcNow;
await _unitOfWork.RefreshTokenRepository
.UpdateOneAsync(refreshToken, cancellationToken);
await _unitOfWork.SaveAsync(cancellationToken);
_unitOfWork.Dispose();
}
}

View File

@ -1,6 +0,0 @@
using MediatR;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RevokeRefreshTokenWithCookie;
public record RevokeRefreshTokenWithCookieCommand : IRequest { }

View File

@ -1,26 +0,0 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RevokeRefreshTokenWithCookie;
public class RevokeRefreshTokenWithCookieCommandAuthorizer :
AbstractRequestAuthorizer<RevokeRefreshTokenWithCookieCommand>
{
private readonly SessionUserService _sessionUserService;
public RevokeRefreshTokenWithCookieCommandAuthorizer(
SessionUserService currentUserService)
{
_sessionUserService = currentUserService;
}
public override void BuildPolicy(RevokeRefreshTokenWithCookieCommand request)
{
UseRequirement(new MustBeAuthenticatedRequirement
{
IsAuthenticated = _sessionUserService.IsAuthenticated
});
}
}

View File

@ -1,28 +0,0 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using MediatR;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RevokeRefreshTokenWithCookie;
public class RevokeRefreshTokenWithCookieCommandHandler :
IRequestHandler<RevokeRefreshTokenWithCookieCommand>
{
private readonly AuthenticationService _authenticationService;
private readonly SessionUserService _sessionUserService;
public RevokeRefreshTokenWithCookieCommandHandler(
AuthenticationService authenticationService,
SessionUserService sessionUserService)
{
_authenticationService = authenticationService;
_sessionUserService = sessionUserService;
}
public async Task Handle(
RevokeRefreshTokenWithCookieCommand request,
CancellationToken cancellationToken)
{
await _authenticationService.RevokeRefreshTokenAsync(
_sessionUserService.RefreshToken, cancellationToken);
}
}

View File

@ -1,10 +0,0 @@
using FluentValidation;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Commands
.RevokeRefreshTokenWithCookie;
public class RevokeRefreshTokenWithCookieCommandValidator :
AbstractValidator<RevokeRefreshTokenWithCookieCommand>
{
public RevokeRefreshTokenWithCookieCommandValidator() { }
}

View File

@ -4,7 +4,7 @@ namespace cuqmbr.TravelGuide.Application.Authenticaion.Queries.Login;
public record LoginQuery : IRequest<TokensModel>
{
public string Email { get; set; }
public string EmailOrUsername { get; set; }
public string Password { get; set; }
}

View File

@ -0,0 +1,12 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Queries.Login;
public class LoginQueryAuthorizer : AbstractRequestAuthorizer<LoginQuery>
{
public override void BuildPolicy(LoginQuery request)
{
UseRequirement(new AllowAllRequirement());
}
}

View File

@ -1,21 +1,140 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Entities;
using MediatR;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Queries.Login;
public class LoginQueryHandler : IRequestHandler<LoginQuery, TokensModel>
{
private readonly AuthenticationService _authenticationService;
private readonly UnitOfWork _unitOfWork;
private readonly PasswordHasherService _passwordHasher;
private readonly JsonWebTokenConfigurationOptions _jwtConfiguration;
public LoginQueryHandler(AuthenticationService authenticationService)
public LoginQueryHandler(UnitOfWork unitOfWork,
PasswordHasherService passwordHasher,
IOptions<ConfigurationOptions> configurationOptions)
{
_authenticationService = authenticationService;
_unitOfWork = unitOfWork;
_passwordHasher = passwordHasher;
_jwtConfiguration = configurationOptions.Value.JsonWebToken;
}
public async Task<TokensModel> Handle(
LoginQuery request, CancellationToken cancellationToken)
{
return await _authenticationService.LoginAsync(
request.Email, request.Password, cancellationToken);
var account = await _unitOfWork.AccountRepository
.GetOneAsync(
a =>
a.Email == request.EmailOrUsername ||
a.Username == request.EmailOrUsername,
a => a.AccountRoles, cancellationToken);
if (account == null)
{
throw new LoginException("No users registered with given email.");
}
var hash = Convert.FromBase64String(account.PasswordHash);
var salt = Convert.FromBase64String(account.PasswordSalt);
var password = Encoding.UTF8.GetBytes(request.Password);
var isValidPassword = await _passwordHasher
.IsValidHashAsync(hash, password, salt, cancellationToken);
if (!isValidPassword)
{
throw new LoginException("Given password is incorrect.");
}
var jwtSecurityToken = await CreateJwtAsync(account, cancellationToken);
var accessToken = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
var refreshToken = (await _unitOfWork.RefreshTokenRepository
.GetPageAsync(
e =>
e.AccountId == account.Id &&
e.RevocationTime == null &&
e.ExpirationTime > DateTimeOffset.UtcNow,
1, int.MaxValue, cancellationToken))
.Items.FirstOrDefault();
if (refreshToken == null)
{
refreshToken = CreateRefreshToken();
refreshToken.AccountId = account.Id;
await _unitOfWork.RefreshTokenRepository
.AddOneAsync(refreshToken, cancellationToken);
}
await _unitOfWork.SaveAsync(cancellationToken);
_unitOfWork.Dispose();
return new TokensModel(accessToken, refreshToken.Value);
}
private async Task<JwtSecurityToken> CreateJwtAsync(
Account account, CancellationToken cancellationToken)
{
var roleIds = account.AccountRoles.Select(ar => ar.RoleId);
var roles = (await _unitOfWork.RoleRepository
.GetPageAsync(
r => roleIds.Contains(r.Id),
1, roleIds.Count(), cancellationToken))
.Items.Select(r => r.Value);
var roleClaims = new List<Claim>();
foreach (var role in roles)
{
roleClaims.Add(new Claim("roles", role.Name));
}
var claims = new List<Claim>()
{
new Claim(JwtRegisteredClaimNames.Sub, account.Guid.ToString()),
new Claim(JwtRegisteredClaimNames.Nickname, account.Username),
new Claim(JwtRegisteredClaimNames.Email, account.Email)
}
.Union(roleClaims);
var expirationDateTimeUtc = DateTime.UtcNow.Add(
_jwtConfiguration.AccessTokenValidity);
var symmetricSecurityKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_jwtConfiguration.IssuerSigningKey));
var signingCredentials = new SigningCredentials(
symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
var jwtSecurityToken = new JwtSecurityToken(
issuer: _jwtConfiguration.Issuer,
audience: _jwtConfiguration.Audience,
claims: claims,
expires: expirationDateTimeUtc,
signingCredentials: signingCredentials);
return jwtSecurityToken;
}
private RefreshToken CreateRefreshToken()
{
var token = RandomNumberGenerator.GetBytes(128 / 8);
return new RefreshToken
{
Guid = Guid.NewGuid(),
Value = Convert.ToBase64String(token),
CreationTime = DateTimeOffset.UtcNow,
ExpirationTime = DateTimeOffset.UtcNow.Add(
_jwtConfiguration.RefreshTokenValidity)
};
}
}

View File

@ -1,15 +1,18 @@
using FluentValidation;
using Microsoft.Extensions.Localization;
namespace cuqmbr.TravelGuide.Application.Authenticaion.Queries.Login;
public class LoginQueryValidator : AbstractValidator<LoginQuery>
{
public LoginQueryValidator()
public LoginQueryValidator(IStringLocalizer localizer)
{
RuleFor(v => v.Email)
.NotEmpty().WithMessage("Email address is required.");
RuleFor(v => v.EmailOrUsername)
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]);
RuleFor(v => v.Password)
.NotEmpty().WithMessage("Password is required.");
.NotEmpty()
.WithMessage(localizer["FluentValidation.NotEmpty"]);
}
}

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Buses.Commands.AddBus;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Domain.Entities;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Buses.Commands.DeleteBus;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
namespace cuqmbr.TravelGuide.Application.Buses.Commands.DeleteBus;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Buses.Commands.UpdateBus;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBus;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using AutoMapper;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBusesPage;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Extensions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Cities.Commands.AddCity;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Domain.Entities;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Cities.Commands.DeleteCity;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
namespace cuqmbr.TravelGuide.Application.Cities.Commands.DeleteCity;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Cities.Commands.UpdateCity;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Exceptions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Cities.Queries.GetCitiesPage;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Extensions;

View File

@ -1,4 +1,4 @@
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
using FluentValidation;
using Microsoft.Extensions.Localization;

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Application.Common.Authorization;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Domain.Enums;
using MediatR.Behaviors.Authorization;
namespace cuqmbr.TravelGuide.Application.Cities.Queries.GetCity;

View File

@ -1,5 +1,5 @@
using MediatR;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using AutoMapper;

View File

@ -1,6 +1,6 @@
using MediatR.Behaviors.Authorization;
using Microsoft.Extensions.Localization;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Domain.Enums;
namespace cuqmbr.TravelGuide.Application.Common.Authorization;

View File

@ -4,6 +4,14 @@ namespace cuqmbr.TravelGuide.Application.Common.FluentValidation;
public static class CustomValidators
{
public static IRuleBuilderOptions<T, string> IsUsername<T>(
this IRuleBuilder<T, string> ruleBuilder)
{
return
ruleBuilder
.Matches(@"^[a-z0-9-_.]*$");
}
// According to RFC 5321.
public static IRuleBuilderOptions<T, string> IsEmail<T>(
this IRuleBuilder<T, string> ruleBuilder)

View File

@ -1,18 +0,0 @@
using cuqmbr.TravelGuide.Application.Authenticaion;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
public interface AuthenticationService
{
Task RegisterAsync(string email, string password,
CancellationToken cancellationToken);
Task<TokensModel> LoginAsync(string email, string password,
CancellationToken cancellationToken);
Task<TokensModel> RenewAccessTokenAsync(string refreshToken,
CancellationToken cancellationToken);
Task RevokeRefreshTokenAsync(string refreshToken,
CancellationToken cancellationToken);
}

View File

@ -1,22 +0,0 @@
using cuqmbr.TravelGuide.Application.Common.Models;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
public interface SessionUserService
{
public int? Id { get; }
public Guid? Uuid { get; }
public string? Email { get; }
public ICollection<IdentityRole> Roles { get; }
public bool IsAuthenticated => Id != null;
public string? AccessToken { get; }
public string? RefreshToken { get; }
}

View File

@ -1,5 +1,5 @@
using AutoMapper;
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
using cuqmbr.TravelGuide.Application.Common.Services;
namespace cuqmbr.TravelGuide.Application.Common.Mappings.Resolvers;

View File

@ -0,0 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface AccountRepository : BaseRepository<Account> { }

View File

@ -0,0 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface AccountRoleRepository : BaseRepository<AccountRole> { }

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface AddressRepository : BaseRepository<Address> { }

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface AircraftRepository : BaseRepository<Aircraft> { }

View File

@ -2,8 +2,7 @@ using System.Linq.Expressions;
using cuqmbr.TravelGuide.Application.Common.Models;
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface BaseRepository<TEntity>
where TEntity : EntityBase

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface BusRepository : BaseRepository<Bus> { }

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface CityRepository : BaseRepository<City> { }

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
namespace cuqmbr.TravelGuide.Application.Common
.Persistence.Repositories;
public interface CompanyRepository : BaseRepository<Company> { }

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface CountryRepository : BaseRepository<Country> { }

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
namespace cuqmbr.TravelGuide.Application.Common
.Persistence.Repositories;
public interface EmployeeRepository : BaseRepository<Employee> { }

View File

@ -0,0 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface RefreshTokenRepository : BaseRepository<RefreshToken> { }

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface RegionRepository : BaseRepository<Region> { }

View File

@ -0,0 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface RoleRepository : BaseRepository<Role> { }

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
namespace cuqmbr.TravelGuide.Application.Common
.Persistence.Repositories;
public interface RouteAddressDetailRepository :

View File

@ -1,7 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface RouteAddressRepository :
BaseRepository<RouteAddress> { }

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface RouteRepository : BaseRepository<Route> { }

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
namespace cuqmbr.TravelGuide.Application.Common
.Persistence.Repositories;
public interface TicketGroupRepository : BaseRepository<TicketGroup> { }

View File

@ -1,6 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
namespace cuqmbr.TravelGuide.Application.Common
.Persistence.Repositories;
public interface TicketRepository : BaseRepository<Ticket> { }

View File

@ -1,6 +1,5 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
.Persistence.Repositories;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface TrainRepository : BaseRepository<Train> { }

View File

@ -0,0 +1,6 @@
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Common.Persistence.Repositories;
public interface VehicleEnrollmentEmployeeRepository :
BaseRepository<VehicleEnrollmentEmployee> { }

Some files were not shown because too many files have changed in this diff Show More