redo
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"email": "sys@t.em",
|
"email": "sys@t.em",
|
||||||
"key": "aa0e0979-99db-42e7-8b60-91c2d055b9d0",
|
"key": "b60e166e-d4a5-416e-a7c9-142d05fb7f31",
|
||||||
"password": "+z1L[oYUupZ>L{4a"
|
"password": "8C3,uTÑ<hñ61qQs3"
|
||||||
}
|
}
|
@@ -5,5 +5,5 @@ namespace back.DTO;
|
|||||||
public class UserDto
|
public class UserDto
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = null!;
|
public string Id { get; set; } = null!;
|
||||||
public ICollection<Role> Roles { get; set; } = [];
|
public ICollection<RoleDto> Roles { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using MCVIngenieros.Transactional.Abstractions;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Transactional.Abstractions;
|
|
||||||
|
|
||||||
namespace back.DataModels;
|
namespace back.DataModels;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
|
using MCVIngenieros.Transactional.Abstractions;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Transactional.Abstractions;
|
|
||||||
|
|
||||||
namespace back.DataModels;
|
namespace back.DataModels;
|
||||||
|
|
||||||
|
@@ -1,10 +1,16 @@
|
|||||||
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace back.DataModels;
|
namespace back.DataModels;
|
||||||
|
|
||||||
|
public record PermissionDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
[Table("Permissions")]
|
[Table("Permissions")]
|
||||||
public partial class Permission: IEquatable<Permission>
|
public partial class Permission : IEntity<Permission>
|
||||||
{
|
{
|
||||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
public string Id { get; set; } = null!;
|
public string Id { get; set; } = null!;
|
||||||
@@ -26,6 +32,32 @@ public partial class Permission: IEquatable<Permission>
|
|||||||
Id == other.Id || GetHashCode() == other.GetHashCode();
|
Id == other.Id || GetHashCode() == other.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsNull => this is null;
|
||||||
|
|
||||||
|
public object Clone() => (Permission)MemberwiseClone();
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is null) return 1;
|
||||||
|
if (obj is not Permission other) throw new ArgumentException("Object is not a Person");
|
||||||
|
return CompareTo(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Permission? other)
|
||||||
|
{
|
||||||
|
if (other is null) return 1;
|
||||||
|
if (ReferenceEquals(this, other)) return 0;
|
||||||
|
return string.Compare(Id, other.Id, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PermissionDto ToDto()
|
||||||
|
{
|
||||||
|
return new PermissionDto
|
||||||
|
{
|
||||||
|
Id = Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Static permissions
|
// Static permissions
|
||||||
public static readonly Permission ViewContentPermission = new() { Id = "1", Name = "VIEW_CONTENT", Description = "Permission to view content" };
|
public static readonly Permission ViewContentPermission = new() { Id = "1", Name = "VIEW_CONTENT", Description = "Permission to view content" };
|
||||||
public static readonly Permission LikeContentPermission = new() { Id = "2", Name = "LIKE_CONTENT", Description = "Permission to like content" };
|
public static readonly Permission LikeContentPermission = new() { Id = "2", Name = "LIKE_CONTENT", Description = "Permission to like content" };
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
|
using MCVIngenieros.Transactional.Abstractions;
|
||||||
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Transactional.Abstractions;
|
|
||||||
using Transactional.Abstractions.Interfaces;
|
|
||||||
|
|
||||||
namespace back.DataModels;
|
namespace back.DataModels;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Transactional.Abstractions.Interfaces;
|
|
||||||
|
|
||||||
namespace back.DataModels;
|
namespace back.DataModels;
|
||||||
|
|
||||||
|
@@ -1,10 +1,17 @@
|
|||||||
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace back.DataModels;
|
namespace back.DataModels;
|
||||||
|
|
||||||
|
public class RoleDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = null!;
|
||||||
|
public List<PermissionDto> Permissions { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
[Table("Roles")]
|
[Table("Roles")]
|
||||||
public partial class Role : IEquatable<Role>
|
public partial class Role : IEntity<Role>
|
||||||
{
|
{
|
||||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
public string Id { get; set; } = null!;
|
public string Id { get; set; } = null!;
|
||||||
@@ -18,7 +25,6 @@ public partial class Role : IEquatable<Role>
|
|||||||
public virtual ICollection<Permission> Permissions { get; set; } = new HashSet<Permission>();
|
public virtual ICollection<Permission> Permissions { get; set; } = new HashSet<Permission>();
|
||||||
public virtual ICollection<User> Users { get; set; } = [];
|
public virtual ICollection<User> Users { get; set; } = [];
|
||||||
|
|
||||||
|
|
||||||
public bool IsAdmin() => BaseRoleModel != null ? BaseRoleModel.IsAdmin() : Id == AdminRole.Id;
|
public bool IsAdmin() => BaseRoleModel != null ? BaseRoleModel.IsAdmin() : Id == AdminRole.Id;
|
||||||
public bool IsContentManager() => BaseRoleModel != null ? BaseRoleModel.IsContentManager() : Id == ContentManagerRole.Id;
|
public bool IsContentManager() => BaseRoleModel != null ? BaseRoleModel.IsContentManager() : Id == ContentManagerRole.Id;
|
||||||
public bool IsUser() => BaseRoleModel != null ? BaseRoleModel.IsUser() : Id == UserRole.Id;
|
public bool IsUser() => BaseRoleModel != null ? BaseRoleModel.IsUser() : Id == UserRole.Id;
|
||||||
@@ -62,6 +68,33 @@ public partial class Role : IEquatable<Role>
|
|||||||
return Id == other.Id || GetHashCode() == other.GetHashCode();
|
return Id == other.Id || GetHashCode() == other.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsNull => this is null;
|
||||||
|
|
||||||
|
public object Clone() => (Role)MemberwiseClone();
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is null) return 1;
|
||||||
|
if (obj is not Role other) throw new ArgumentException("Object is not a Person");
|
||||||
|
return CompareTo(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Role? other)
|
||||||
|
{
|
||||||
|
if (other is null) return 1;
|
||||||
|
if (ReferenceEquals(this, other)) return 0;
|
||||||
|
return string.Compare(Id, other.Id, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoleDto ToDto()
|
||||||
|
{
|
||||||
|
return new RoleDto
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
Permissions = [.. Permissions.Select(p => p.ToDto())]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly Role UserRole = new(
|
public static readonly Role UserRole = new(
|
||||||
"1", "User", "Role for regular users",
|
"1", "User", "Role for regular users",
|
||||||
[
|
[
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
using back.DTO;
|
using back.DTO;
|
||||||
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Transactional.Abstractions.Interfaces;
|
|
||||||
|
|
||||||
namespace back.DataModels;
|
namespace back.DataModels;
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ public class User : IEntity<User>
|
|||||||
public UserDto ToDto() => new()
|
public UserDto ToDto() => new()
|
||||||
{
|
{
|
||||||
Id = Id,
|
Id = Id,
|
||||||
Roles = Roles
|
Roles = [.. Roles.Select(r => r.ToDto())]
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool IsAdmin() => Roles.Any(r => r.IsAdmin());
|
public bool IsAdmin() => Roles.Any(r => r.IsAdmin());
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
using back.ServicesExtensions;
|
using back.ServicesExtensions;
|
||||||
using healthchecks;
|
using MCVIngenieros.Healthchecks;
|
||||||
|
|
||||||
namespace back;
|
namespace back;
|
||||||
|
|
||||||
@@ -13,11 +13,7 @@ public class Program
|
|||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
builder.Services.AddHealthChecks(options => {
|
builder.Services.AddHealthChecksSupport().DiscoverHealthChecks();
|
||||||
options.CacheDuration = TimeSpan.FromMinutes(30);
|
|
||||||
options.Timeout = TimeSpan.FromSeconds(5);
|
|
||||||
options.AssembliesToScan = [typeof(Program).Assembly];
|
|
||||||
}).DiscoverHealthChecks();
|
|
||||||
|
|
||||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
@@ -3,8 +3,8 @@ using System.Text.Json.Serialization;
|
|||||||
using back.services.engine.SystemUser;
|
using back.services.engine.SystemUser;
|
||||||
using DependencyInjector;
|
using DependencyInjector;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Transactional.Abstractions.Interfaces;
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
using Transactional.Implementations.EntityFramework;
|
using MCVIngenieros.Transactional.Implementations.EntityFramework;
|
||||||
|
|
||||||
namespace back.ServicesExtensions;
|
namespace back.ServicesExtensions;
|
||||||
|
|
||||||
|
@@ -19,10 +19,15 @@
|
|||||||
"EnableSsl": true
|
"EnableSsl": true
|
||||||
},
|
},
|
||||||
"HealthChecksConfigs": {
|
"HealthChecksConfigs": {
|
||||||
|
"CacheDuration": "00:30:00",
|
||||||
|
"Timeout": "00:00:05",
|
||||||
|
"AssembliesToScan": [
|
||||||
|
"back"
|
||||||
|
],
|
||||||
"Sqlite": {
|
"Sqlite": {
|
||||||
"RetryAttempts" : 2,
|
"RetryAttempts": 2,
|
||||||
"Timeout" : "00:05:00",
|
"Timeout": "00:05:00",
|
||||||
"RetryDelay" : "00:00:10",
|
"RetryDelay": "00:00:10",
|
||||||
"Severity": "Info"
|
"Severity": "Info"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||||
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.1" />
|
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.1" />
|
||||||
<PackageReference Include="Mapster.EFCore" Version="5.1.1" />
|
<PackageReference Include="Mapster.EFCore" Version="5.1.1" />
|
||||||
|
<PackageReference Include="MCVIngenieros.Healthchecks" Version="0.0.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.8" />
|
||||||
@@ -33,7 +34,6 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.8" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||||
<PackageReference Include="Oracle.EntityFrameworkCore" Version="9.23.90" />
|
<PackageReference Include="Oracle.EntityFrameworkCore" Version="9.23.90" />
|
||||||
@@ -48,8 +48,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\nuget\DependencyInjector\DependencyInjector.csproj" />
|
<ProjectReference Include="..\..\nuget\DependencyInjector\DependencyInjector.csproj" />
|
||||||
<ProjectReference Include="..\..\nuget\healthchecks\healthchecks.csproj" />
|
<ProjectReference Include="..\..\nuget\Transactional\MCVIngenieros.Transactional.csproj" />
|
||||||
<ProjectReference Include="..\..\nuget\Transactional\Transactional.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -5,11 +5,11 @@ VisualStudioVersion = 17.14.36401.2
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "back", "back.csproj", "{392278F3-4B36-47F4-AD31-5FBFCC181AD4}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "back", "back.csproj", "{392278F3-4B36-47F4-AD31-5FBFCC181AD4}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Transactional", "..\..\nuget\Transactional\Transactional.csproj", "{ED76105A-5E6F-4997-86FE-6A7902A2AEBA}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MCVIngenieros.Transactional", "..\..\nuget\Transactional\MCVIngenieros.Transactional.csproj", "{ED76105A-5E6F-4997-86FE-6A7902A2AEBA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependencyInjector", "..\..\nuget\DependencyInjector\DependencyInjector.csproj", "{DBDF84A4-235C-4F29-8626-5BD1DC255970}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependencyInjector", "..\..\nuget\DependencyInjector\DependencyInjector.csproj", "{DBDF84A4-235C-4F29-8626-5BD1DC255970}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "healthchecks", "..\..\nuget\healthchecks\healthchecks.csproj", "{B21E2BEF-17B7-4981-9843-C0CC36D67010}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Presentation", "..\backend\Presentation\Presentation.csproj", "{F1DD9D2A-0467-41EE-B3BB-303F1A0C18D6}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@@ -29,10 +29,10 @@ Global
|
|||||||
{DBDF84A4-235C-4F29-8626-5BD1DC255970}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{DBDF84A4-235C-4F29-8626-5BD1DC255970}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{DBDF84A4-235C-4F29-8626-5BD1DC255970}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{DBDF84A4-235C-4F29-8626-5BD1DC255970}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{DBDF84A4-235C-4F29-8626-5BD1DC255970}.Release|Any CPU.Build.0 = Release|Any CPU
|
{DBDF84A4-235C-4F29-8626-5BD1DC255970}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{B21E2BEF-17B7-4981-9843-C0CC36D67010}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{F1DD9D2A-0467-41EE-B3BB-303F1A0C18D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B21E2BEF-17B7-4981-9843-C0CC36D67010}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{F1DD9D2A-0467-41EE-B3BB-303F1A0C18D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B21E2BEF-17B7-4981-9843-C0CC36D67010}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{F1DD9D2A-0467-41EE-B3BB-303F1A0C18D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B21E2BEF-17B7-4981-9843-C0CC36D67010}.Release|Any CPU.Build.0 = Release|Any CPU
|
{F1DD9D2A-0467-41EE-B3BB-303F1A0C18D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
44
back/controllers/AuthController.cs
Normal file
44
back/controllers/AuthController.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace back.controllers;
|
||||||
|
|
||||||
|
public class ValidationErrors
|
||||||
|
{
|
||||||
|
public string? Field { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExecutionErrors
|
||||||
|
{
|
||||||
|
public Exception? Exception { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ResponseBase
|
||||||
|
{
|
||||||
|
public object? Data { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public int StatusCode { get; set; }
|
||||||
|
public ValidationErrors[] ValidationErrors { get; set; }
|
||||||
|
public ExecutionErrors[] ExecutionErrors { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record LoginRequest(string Username, string Password);
|
||||||
|
|
||||||
|
[ApiController, Route("api/[controller]")]
|
||||||
|
public class AuthController(IAuthService authService) : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly IAuthService _authService = authService;
|
||||||
|
|
||||||
|
[HttpPost, Route("login")]
|
||||||
|
public async Task<IActionResult> Login([FromBody] LoginRequest loginRequest)
|
||||||
|
{
|
||||||
|
// validar que el usuario y la contraseña sean correctos
|
||||||
|
// obtener el token JWT encriptado
|
||||||
|
// obtener el refresh token
|
||||||
|
// devolver el token JWT y el refresh token en los headers de las respuestas
|
||||||
|
// devolver datos del usuario en el body de la respuesta
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,6 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using back.DTO;
|
|
||||||
using back.services.bussines;
|
using back.services.bussines;
|
||||||
using back.services.bussines.UserService;
|
using back.services.bussines.UserService;
|
||||||
using Mapster;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace back.controllers;
|
namespace back.controllers;
|
||||||
@@ -53,7 +51,7 @@ public class UsersController(IUserService user) : ControllerBase
|
|||||||
var systemUser = await _user.ValidateSystemUser(user.Email, user.Password, user.SystemKey, clientId);
|
var systemUser = await _user.ValidateSystemUser(user.Email, user.Password, user.SystemKey, clientId);
|
||||||
if (systemUser == null)
|
if (systemUser == null)
|
||||||
return Unauthorized(Errors.Unauthorized.Description);
|
return Unauthorized(Errors.Unauthorized.Description);
|
||||||
return Ok(systemUser.Adapt<UserDto>());
|
return Ok(systemUser.ToDto());
|
||||||
}
|
}
|
||||||
|
|
||||||
var existingUser = await _user.Login(user.Email, user.Password, clientId);
|
var existingUser = await _user.Login(user.Email, user.Password, clientId);
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
using HealthChecksConfigsBase = healthchecks.Options.HealthChecksConfigs;
|
namespace back.healthchecks.Options;
|
||||||
|
|
||||||
namespace back.healthchecks.Options;
|
public partial class HealthChecksConfigs : MCVIngenieros.Healthchecks.Options.HealthChecksConfigs
|
||||||
|
|
||||||
public partial class HealthChecksConfigs : HealthChecksConfigsBase
|
|
||||||
{
|
{
|
||||||
public const string Sqlite = "Sqlite";
|
public const string Sqlite = "Sqlite";
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
using back.Options;
|
using back.healthchecks.Options;
|
||||||
using healthchecks;
|
using back.Options;
|
||||||
using healthchecks.Abstracts;
|
using MCVIngenieros.Healthchecks;
|
||||||
using back.healthchecks.Options;
|
using MCVIngenieros.Healthchecks.Abstracts;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace back.healthchecks;
|
namespace back.healthchecks;
|
||||||
|
|
||||||
public class SqliteHealthCheck(IOptionsMonitor<DatabaseConfig> databaseConfig, IOptionsMonitor<HealthChecksConfigs> healthchecksConfig) : IHealthCheck
|
public class SqliteHealthCheck(IOptionsMonitor<DatabaseConfig> databaseConfig, IOptionsMonitor<HealthChecksConfigs> healthchecksConfig) : HealthCheck
|
||||||
{
|
{
|
||||||
private readonly DatabaseConfig databaseConfig = databaseConfig.Get(DatabaseConfig.DataStorage);
|
private readonly DatabaseConfig databaseConfig = databaseConfig.Get(DatabaseConfig.DataStorage);
|
||||||
private readonly HealthChecksConfigs hcConfig = healthchecksConfig.Get(HealthChecksConfigs.Sqlite);
|
private readonly HealthChecksConfigs hcConfig = healthchecksConfig.Get(HealthChecksConfigs.Sqlite);
|
||||||
@@ -17,7 +17,7 @@ public class SqliteHealthCheck(IOptionsMonitor<DatabaseConfig> databaseConfig, I
|
|||||||
public TimeSpan? RetryDelay => hcConfig.RetryDelay ?? TimeSpan.FromSeconds(1);
|
public TimeSpan? RetryDelay => hcConfig.RetryDelay ?? TimeSpan.FromSeconds(1);
|
||||||
public HealthCheckSeverity? Severity => hcConfig.Severity ?? HealthCheckSeverity.Critical;
|
public HealthCheckSeverity? Severity => hcConfig.Severity ?? HealthCheckSeverity.Critical;
|
||||||
|
|
||||||
public Task<HealthCheckResult> CheckAsync(CancellationToken cancellationToken = default)
|
public override Task<HealthCheckResult> CheckAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var isHealthy = false;
|
var isHealthy = false;
|
||||||
var details = string.Empty;
|
var details = string.Empty;
|
||||||
@@ -43,7 +43,7 @@ public class SqliteHealthCheck(IOptionsMonitor<DatabaseConfig> databaseConfig, I
|
|||||||
details = $"Failed to connect to SQLite database: {ex.Message}";
|
details = $"Failed to connect to SQLite database: {ex.Message}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(new HealthCheckResult(isHealthy, null)
|
return Task.FromResult(new HealthCheckResult(isHealthy)
|
||||||
{
|
{
|
||||||
Details = details,
|
Details = details,
|
||||||
Severity = isHealthy ? HealthCheckSeverity.Info : HealthCheckSeverity.Critical
|
Severity = isHealthy ? HealthCheckSeverity.Info : HealthCheckSeverity.Critical
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.persistance.blob;
|
namespace back.persistance.blob;
|
||||||
|
|
||||||
|
@@ -49,15 +49,6 @@ public partial class DataContext : DbContext
|
|||||||
relationEstablisher?.EstablishRelation(modelBuilder);
|
relationEstablisher?.EstablishRelation(modelBuilder);
|
||||||
});
|
});
|
||||||
|
|
||||||
//typeof(ISeeder).Assembly.GetExportedTypes()
|
|
||||||
// .Where(t => typeof(ISeeder).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
|
|
||||||
// .ToList()
|
|
||||||
// .ForEach(seederType =>
|
|
||||||
// {
|
|
||||||
// var seeder = (ISeeder?)Activator.CreateInstance(seederType);
|
|
||||||
// seeder?.Seed(modelBuilder);
|
|
||||||
// });
|
|
||||||
|
|
||||||
OnModelCreatingPartial(modelBuilder);
|
OnModelCreatingPartial(modelBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
using back.DataModels;
|
||||||
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
|
|
||||||
|
namespace back.persistance.data.repositories.Abstracts;
|
||||||
|
|
||||||
|
public interface IPermissionRepository : IRepository<Permission>, IScoped
|
||||||
|
{
|
||||||
|
Task SeedDefaultPermissions();
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
using Transactional.Abstractions.Interfaces;
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
|
|
||||||
namespace back.persistance.data.repositories.Abstracts;
|
namespace back.persistance.data.repositories.Abstracts;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
using Transactional.Abstractions.Interfaces;
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
|
|
||||||
namespace back.persistance.data.repositories.Abstracts;
|
namespace back.persistance.data.repositories.Abstracts;
|
||||||
|
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
using back.DataModels;
|
||||||
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
|
|
||||||
|
namespace back.persistance.data.repositories.Abstracts;
|
||||||
|
|
||||||
|
public interface IRoleRepository : IRepository<Role>, IScoped
|
||||||
|
{
|
||||||
|
Task SeedDefaultRoles();
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
using Transactional.Abstractions.Interfaces;
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
|
|
||||||
namespace back.persistance.data.repositories.Abstracts;
|
namespace back.persistance.data.repositories.Abstracts;
|
||||||
|
|
||||||
|
34
back/persistance/data/repositories/PermissionRepository.cs
Normal file
34
back/persistance/data/repositories/PermissionRepository.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using back.DataModels;
|
||||||
|
using back.persistance.data.repositories.Abstracts;
|
||||||
|
using MCVIngenieros.Transactional.Implementations.EntityFramework;
|
||||||
|
|
||||||
|
namespace back.persistance.data.repositories;
|
||||||
|
|
||||||
|
public class PermissionRepository(DataContext context) : ReadWriteRepository<Permission>(context), IPermissionRepository
|
||||||
|
{
|
||||||
|
// Implement methods specific to Photo repository if needed
|
||||||
|
public async Task SeedDefaultPermissions()
|
||||||
|
{
|
||||||
|
var defaultPermissions = new List<Permission>
|
||||||
|
{
|
||||||
|
Permission.ViewContentPermission,
|
||||||
|
Permission.LikeContentPermission,
|
||||||
|
Permission.EditContentPermission,
|
||||||
|
Permission.DeleteContentPermission,
|
||||||
|
Permission.CreateContentPermission,
|
||||||
|
Permission.EditUserPermission,
|
||||||
|
Permission.DeleteUserPermission,
|
||||||
|
Permission.DisableUserPermission,
|
||||||
|
Permission.CreateUserPermission,
|
||||||
|
Permission.EditWebConfigPermission
|
||||||
|
};
|
||||||
|
foreach (var permission in defaultPermissions)
|
||||||
|
{
|
||||||
|
if (!Entities.Any(p => p.Id == permission.Id))
|
||||||
|
{
|
||||||
|
Entities.Add(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using back.persistance.data.repositories.Abstracts;
|
using back.persistance.data.repositories.Abstracts;
|
||||||
using Transactional.Implementations.EntityFramework;
|
using MCVIngenieros.Transactional.Implementations.EntityFramework;
|
||||||
|
|
||||||
namespace back.persistance.data.repositories;
|
namespace back.persistance.data.repositories;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using back.persistance.data.repositories.Abstracts;
|
using back.persistance.data.repositories.Abstracts;
|
||||||
using Transactional.Implementations.EntityFramework;
|
using MCVIngenieros.Transactional.Implementations.EntityFramework;
|
||||||
|
|
||||||
namespace back.persistance.data.repositories;
|
namespace back.persistance.data.repositories;
|
||||||
|
|
||||||
|
27
back/persistance/data/repositories/RoleRepository.cs
Normal file
27
back/persistance/data/repositories/RoleRepository.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using back.DataModels;
|
||||||
|
using back.persistance.data.repositories.Abstracts;
|
||||||
|
using MCVIngenieros.Transactional.Implementations.EntityFramework;
|
||||||
|
|
||||||
|
namespace back.persistance.data.repositories;
|
||||||
|
|
||||||
|
public class RoleRepository(DataContext context) : ReadWriteRepository<Role>(context), IRoleRepository
|
||||||
|
{
|
||||||
|
// Implement methods specific to Photo repository if needed
|
||||||
|
public async Task SeedDefaultRoles()
|
||||||
|
{
|
||||||
|
var defaultRoles = new List<Role>
|
||||||
|
{
|
||||||
|
Role.AdminRole,
|
||||||
|
Role.UserRole,
|
||||||
|
Role.ContentManagerRole
|
||||||
|
};
|
||||||
|
foreach (var role in defaultRoles)
|
||||||
|
{
|
||||||
|
if (!Entities.Any(p => p.Id == role.Id))
|
||||||
|
{
|
||||||
|
Entities.Add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,11 +1,13 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using back.persistance.data.repositories.Abstracts;
|
using back.persistance.data.repositories.Abstracts;
|
||||||
|
using MCVIngenieros.Transactional.Implementations.EntityFramework;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Transactional.Implementations.EntityFramework;
|
|
||||||
|
|
||||||
namespace back.persistance.data.repositories;
|
namespace back.persistance.data.repositories;
|
||||||
|
|
||||||
public class UserRepository(DataContext context) : ReadWriteRepository<User>(context), IUserRepository
|
public class UserRepository(
|
||||||
|
DataContext context
|
||||||
|
) : ReadWriteRepository<User>(context), IUserRepository
|
||||||
{
|
{
|
||||||
public async Task<User?> GetByEmail(string email)
|
public async Task<User?> GetByEmail(string email)
|
||||||
{
|
{
|
||||||
@@ -39,7 +41,10 @@ public class UserRepository(DataContext context) : ReadWriteRepository<User>(con
|
|||||||
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) return null;
|
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) return null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await Entities.FirstOrDefaultAsync(u => u.Email == email && u.Password == password);
|
return await Entities
|
||||||
|
.Include(u => u.Roles)
|
||||||
|
.ThenInclude(r => r.Permissions)
|
||||||
|
.FirstOrDefaultAsync(u => u.Email == email && u.Password == password);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@@ -1,23 +1,23 @@
|
|||||||
//using back.DataModels;
|
using back.DataModels;
|
||||||
//using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
//namespace back.persistance.data.seeders;
|
namespace back.persistance.data.seeders;
|
||||||
|
|
||||||
//public class PermissionSeeder : ISeeder
|
public class PermissionSeeder : ISeeder
|
||||||
//{
|
{
|
||||||
// public void Seed(ModelBuilder modelBuilder)
|
public void Seed(ModelBuilder modelBuilder)
|
||||||
// {
|
{
|
||||||
// modelBuilder.Entity<Permission>().HasData(
|
modelBuilder.Entity<Permission>().HasData(
|
||||||
// Permission.ViewContentPermission,
|
Permission.ViewContentPermission,
|
||||||
// Permission.LikeContentPermission,
|
Permission.LikeContentPermission,
|
||||||
// Permission.EditContentPermission,
|
Permission.EditContentPermission,
|
||||||
// Permission.DeleteContentPermission,
|
Permission.DeleteContentPermission,
|
||||||
// Permission.CreateContentPermission,
|
Permission.CreateContentPermission,
|
||||||
// Permission.EditUserPermission,
|
Permission.EditUserPermission,
|
||||||
// Permission.DeleteUserPermission,
|
Permission.DeleteUserPermission,
|
||||||
// Permission.DisableUserPermission,
|
Permission.DisableUserPermission,
|
||||||
// Permission.CreateUserPermission,
|
Permission.CreateUserPermission,
|
||||||
// Permission.EditWebConfigPermission
|
Permission.EditWebConfigPermission
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
//}
|
}
|
@@ -1,16 +1,16 @@
|
|||||||
//using back.DataModels;
|
using back.DataModels;
|
||||||
//using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
//namespace back.persistance.data.seeders;
|
namespace back.persistance.data.seeders;
|
||||||
|
|
||||||
//public class RoleSeeder : ISeeder
|
public class RoleSeeder : ISeeder
|
||||||
//{
|
{
|
||||||
// public void Seed(ModelBuilder modelBuilder)
|
public void Seed(ModelBuilder modelBuilder)
|
||||||
// {
|
{
|
||||||
// modelBuilder.Entity<Permission>().HasData(
|
modelBuilder.Entity<Permission>().HasData(
|
||||||
// new Role { Id = "1", Name = "User", Description = "Role for regular users", BaseRoleModelId = null },
|
new Role { Id = "1", Name = "User", Description = "Role for regular users", BaseRoleModelId = null },
|
||||||
// new Role { Id = "2", Name = "Content Manager", Description = "Role for managing content", BaseRoleModelId = "1" },
|
new Role { Id = "2", Name = "Content Manager", Description = "Role for managing content", BaseRoleModelId = "1" },
|
||||||
// new Role { Id = "3", Name = "Admin", Description = "Administrator role with full permissions", BaseRoleModelId = "2" }
|
new Role { Id = "3", Name = "Admin", Description = "Administrator role with full permissions", BaseRoleModelId = "2" }
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
//}
|
}
|
@@ -1,14 +1,14 @@
|
|||||||
using back.DataModels;
|
//using back.DataModels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
//using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace back.persistance.data.seeders;
|
//namespace back.persistance.data.seeders;
|
||||||
|
|
||||||
public class SystemUserSeeder : ISeeder
|
//public class SystemUserSeeder : ISeeder
|
||||||
{
|
//{
|
||||||
public void Seed(ModelBuilder modelBuilder)
|
// public void Seed(ModelBuilder modelBuilder)
|
||||||
{
|
// {
|
||||||
modelBuilder.Entity<Permission>().HasData(
|
// modelBuilder.Entity<Permission>().HasData(
|
||||||
User.SystemUser
|
// User.SystemUser
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
//}
|
@@ -1,6 +1,6 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using back.DTO;
|
using back.DTO;
|
||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.services.bussines.PhotoService;
|
namespace back.services.bussines.PhotoService;
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
using back.DataModels;
|
using back.DataModels;
|
||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.services.bussines.UserService;
|
namespace back.services.bussines.UserService;
|
||||||
|
|
||||||
|
@@ -136,6 +136,7 @@ public class UserService(
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return await Login(user.Email!, decryptedPassword);
|
var loggedUser = await Login(user.Email!, decryptedPassword);
|
||||||
|
return loggedUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.services.engine.Crypto;
|
namespace back.services.engine.Crypto;
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.services.engine.ImageResizer;
|
namespace back.services.engine.ImageResizer;
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.services.engine.PasswordGenerator;
|
namespace back.services.engine.PasswordGenerator;
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.services.engine.SystemUser;
|
namespace back.services.engine.SystemUser;
|
||||||
|
|
||||||
|
@@ -4,8 +4,8 @@ using back.persistance.data;
|
|||||||
using back.persistance.data.repositories.Abstracts;
|
using back.persistance.data.repositories.Abstracts;
|
||||||
using back.services.engine.Crypto;
|
using back.services.engine.Crypto;
|
||||||
using back.services.engine.PasswordGenerator;
|
using back.services.engine.PasswordGenerator;
|
||||||
|
using MCVIngenieros.Transactional.Abstractions.Interfaces;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Transactional.Abstractions.Interfaces;
|
|
||||||
|
|
||||||
namespace back.services.engine.SystemUser;
|
namespace back.services.engine.SystemUser;
|
||||||
|
|
||||||
@@ -14,13 +14,16 @@ public class SystemUserGenerator(
|
|||||||
JsonSerializerOptions jsonSerializerOptions,
|
JsonSerializerOptions jsonSerializerOptions,
|
||||||
IUserRepository userRepository,
|
IUserRepository userRepository,
|
||||||
IPersonRepository personRepository,
|
IPersonRepository personRepository,
|
||||||
|
IRoleRepository roleRepository,
|
||||||
|
IPermissionRepository permissionRepository,
|
||||||
ICryptoService cryptoService,
|
ICryptoService cryptoService,
|
||||||
IBlobStorageService blobStorageService,
|
IBlobStorageService blobStorageService,
|
||||||
IPasswordGenerator passwordGenerator) : ISystemUserGenerator
|
IPasswordGenerator passwordGenerator) : ISystemUserGenerator
|
||||||
{
|
{
|
||||||
public async Task GenerateAsync()
|
public async Task GenerateAsync()
|
||||||
{
|
{
|
||||||
var systemKey = new SystemKey() {
|
var systemKey = new SystemKey()
|
||||||
|
{
|
||||||
Password = passwordGenerator.Generate(16),
|
Password = passwordGenerator.Generate(16),
|
||||||
};
|
};
|
||||||
var systemKeyJson = JsonSerializer.Serialize(systemKey, options: jsonSerializerOptions);
|
var systemKeyJson = JsonSerializer.Serialize(systemKey, options: jsonSerializerOptions);
|
||||||
@@ -42,6 +45,8 @@ public class SystemUserGenerator(
|
|||||||
{
|
{
|
||||||
await transactional.DoTransaction(async () =>
|
await transactional.DoTransaction(async () =>
|
||||||
{
|
{
|
||||||
|
await permissionRepository.SeedDefaultPermissions();
|
||||||
|
await roleRepository.SeedDefaultRoles();
|
||||||
await personRepository.Insert(Person.SystemPerson);
|
await personRepository.Insert(Person.SystemPerson);
|
||||||
await userRepository.Insert(User.SystemUser);
|
await userRepository.Insert(User.SystemUser);
|
||||||
});
|
});
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using DependencyInjector.Lifetimes;
|
using DependencyInjector.Abstractions.Lifetimes;
|
||||||
|
|
||||||
namespace back.services.engine.mailing;
|
namespace back.services.engine.mailing;
|
||||||
|
|
||||||
|
8
backend/Presentation/Controllers/AuthController.cs
Normal file
8
backend/Presentation/Controllers/AuthController.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Presentation.Controllers;
|
||||||
|
|
||||||
|
public class AuthController : Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Presentation.Infraestructura.Responses;
|
||||||
|
|
||||||
|
public sealed class ExecutionError(string message)
|
||||||
|
{
|
||||||
|
public string Message { get; set; } = message;
|
||||||
|
}
|
29
backend/Presentation/Infraestructura/Responses/Response.cs
Normal file
29
backend/Presentation/Infraestructura/Responses/Response.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Presentation.Infraestructura.Responses;
|
||||||
|
|
||||||
|
public sealed class Response<T>
|
||||||
|
{
|
||||||
|
public bool IsSuccess { get; set; }
|
||||||
|
public HttpStatusCode StatusCode { get; set; }
|
||||||
|
public T? Data { get; set; }
|
||||||
|
public ValidationError[]? ValidationErrors { get; set; }
|
||||||
|
public ExecutionError[]? ExecutionErrors { get; set; }
|
||||||
|
|
||||||
|
public static Response<T> Success(T result, HttpStatusCode statusCode = HttpStatusCode.OK) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
IsSuccess = true,
|
||||||
|
StatusCode = statusCode,
|
||||||
|
Data = result
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Response<T> Failure(HttpStatusCode statusCode = HttpStatusCode.InternalServerError, ValidationError[]? validationErrors = null, ExecutionError[]? executionErrors = null) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
IsSuccess = false,
|
||||||
|
StatusCode = statusCode,
|
||||||
|
ValidationErrors = validationErrors,
|
||||||
|
ExecutionErrors = executionErrors
|
||||||
|
};
|
||||||
|
}
|
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Presentation.Infraestructura.Responses;
|
||||||
|
|
||||||
|
public sealed class ValidationError(string fieldName, string message)
|
||||||
|
{
|
||||||
|
public string Field { get; set; } = fieldName;
|
||||||
|
public string Message { get; set; } = message;
|
||||||
|
}
|
34
backend/Presentation/Presentation.csproj
Normal file
34
backend/Presentation/Presentation.csproj
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.8" />
|
||||||
|
<PackageReference Include="OpenTelemetry" Version="1.12.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Api" Version="1.12.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Api.ProviderBuilderExtensions" Version="1.12.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
||||||
|
<PackageReference Include="Serilog" Version="4.3.0" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Process" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.2" />
|
||||||
|
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
96
backend/Presentation/Program.cs
Normal file
96
backend/Presentation/Program.cs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
using OpenTelemetry.Resources;
|
||||||
|
using OpenTelemetry.Trace;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Events;
|
||||||
|
using Serilog.Sinks.OpenTelemetry;
|
||||||
|
|
||||||
|
namespace Presentation
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
// Configura Serilog como logger global antes de crear el builder
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.OpenTelemetry(options =>
|
||||||
|
{
|
||||||
|
options.Endpoint = "http://localhost:4317"; // OTLP endpoint
|
||||||
|
options.Protocol = OtlpProtocol.Grpc;
|
||||||
|
options.ResourceAttributes = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["service.name"] = "mmorales.photo-backend"
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Starting up");
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
builder.Host.UseSerilog(); // Usa Serilog como proveedor de logs por defecto
|
||||||
|
|
||||||
|
builder.Services.AddProblemDetails(options =>
|
||||||
|
options.CustomizeProblemDetails =
|
||||||
|
ctx => ctx.ProblemDetails.Extensions.Add("traceId", ctx.HttpContext.TraceIdentifier)
|
||||||
|
);
|
||||||
|
builder.Services.AddOpenTelemetry()
|
||||||
|
.WithTracing(tracerProviderBuilder =>
|
||||||
|
{
|
||||||
|
tracerProviderBuilder
|
||||||
|
.SetResourceBuilder(ResourceBuilder.CreateDefault()
|
||||||
|
.AddService(builder.Environment.ApplicationName))
|
||||||
|
.AddAspNetCoreInstrumentation() // Traza todas las peticiones HTTP entrantes
|
||||||
|
.AddHttpClientInstrumentation() // Traza las llamadas HttpClient salientes
|
||||||
|
.AddOtlpExporter(opt =>
|
||||||
|
{
|
||||||
|
opt.Endpoint = new Uri("http://localhost:4317"); // Direcci<63>n del colector OTel
|
||||||
|
})
|
||||||
|
.AddConsoleExporter(); // Exporta trazas tambi<62>n a consola para desarrollo
|
||||||
|
});
|
||||||
|
// Add services to the container.
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||||
|
builder.Services.AddOpenApi();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
if (!app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseExceptionHandler();
|
||||||
|
app.UseHsts();
|
||||||
|
}
|
||||||
|
app.UseStatusCodePages();
|
||||||
|
|
||||||
|
app.UseAuthentication(); // Habilita autenticaci<63>n
|
||||||
|
app.UseAuthorization(); // Habilita autorizaci<63>n
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.MapOpenApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Application start-up failed");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
backend/Presentation/Properties/launchSettings.json
Normal file
23
backend/Presentation/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"applicationUrl": "http://localhost:5101",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"applicationUrl": "https://localhost:7265;http://localhost:5101",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
backend/Presentation/appsettings.Development.json
Normal file
8
backend/Presentation/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
backend/Presentation/appsettings.json
Normal file
9
backend/Presentation/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
@@ -1,3 +1,6 @@
|
|||||||
<div class="admin-panel-link">
|
<svg-button
|
||||||
<a href="/admin">Admin</a>
|
label="Panel de Administración"
|
||||||
</div>
|
routerLink="/admin"
|
||||||
|
text="Panel de Administración"
|
||||||
|
icon="assets/icons/book-section-svgrepo-com.svg"
|
||||||
|
></svg-button>
|
||||||
|
Before Width: | Height: | Size: 67 B After Width: | Height: | Size: 169 B |
@@ -1,11 +1,10 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { SvgButton } from '../../../utils/svg-button/svg-button';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'admin-panel-link',
|
selector: 'admin-panel-link',
|
||||||
imports: [],
|
imports: [SvgButton],
|
||||||
templateUrl: './admin-panel-link.html',
|
templateUrl: './admin-panel-link.html',
|
||||||
styleUrl: './admin-panel-link.scss'
|
styleUrl: './admin-panel-link.scss',
|
||||||
})
|
})
|
||||||
export class AdminPanelLink {
|
export class AdminPanelLink {}
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -1,3 +1,6 @@
|
|||||||
<div class="content-manager-panel-link">
|
<svg-button
|
||||||
<a href="/content-manager">Contenido</a>
|
label="Panel de Contenido"
|
||||||
</div>
|
routerLink="/content-manager"
|
||||||
|
text="Panel de Contenido"
|
||||||
|
icon="assets/icons/book-section-svgrepo-com.svg"
|
||||||
|
></svg-button>
|
||||||
|
Before Width: | Height: | Size: 91 B After Width: | Height: | Size: 167 B |
@@ -1,11 +1,10 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { SvgButton } from '../../../utils/svg-button/svg-button';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'content-manager-panel-link',
|
selector: 'content-manager-panel-link',
|
||||||
imports: [],
|
imports: [SvgButton],
|
||||||
templateUrl: './content-manager-panel-link.html',
|
templateUrl: './content-manager-panel-link.html',
|
||||||
styleUrl: './content-manager-panel-link.scss'
|
styleUrl: './content-manager-panel-link.scss',
|
||||||
})
|
})
|
||||||
export class ContentManagerPanelLink {
|
export class ContentManagerPanelLink {}
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -12,7 +12,6 @@ import { OnInit } from '@angular/core';
|
|||||||
import { userModel } from '../../../models/userModel';
|
import { userModel } from '../../../models/userModel';
|
||||||
import { ServicesLink } from '../services-link/services-link';
|
import { ServicesLink } from '../services-link/services-link';
|
||||||
import { Router, NavigationEnd } from '@angular/router';
|
import { Router, NavigationEnd } from '@angular/router';
|
||||||
import { R } from '@angular/cdk/keycodes';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'custom-header',
|
selector: 'custom-header',
|
||||||
|
@@ -1,3 +1,6 @@
|
|||||||
<div class="user-galleries-link">
|
<svg-button
|
||||||
<a href="/galeria">Galería</a>
|
label="Galerías"
|
||||||
</div>
|
routerLink="/my-galleries"
|
||||||
|
text="Galerías"
|
||||||
|
icon="assets/icons/book-section-svgrepo-com.svg"
|
||||||
|
></svg-button>
|
||||||
|
Before Width: | Height: | Size: 75 B After Width: | Height: | Size: 146 B |
@@ -1,11 +1,10 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
|
import { SvgButton } from '../../../utils/svg-button/svg-button';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'user-galleries-link',
|
selector: 'user-galleries-link',
|
||||||
imports: [],
|
imports: [SvgButton],
|
||||||
templateUrl: './user-galleries-link.html',
|
templateUrl: './user-galleries-link.html',
|
||||||
styleUrl: './user-galleries-link.scss'
|
styleUrl: './user-galleries-link.scss',
|
||||||
})
|
})
|
||||||
export class UserGalleriesLink {
|
export class UserGalleriesLink {}
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -39,9 +39,10 @@ export class userService {
|
|||||||
systemKey: encryptedSystemKey,
|
systemKey: encryptedSystemKey,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const { jwt, refresh, usermodel } = response.data;
|
const { id, roles } = response.data;
|
||||||
localStorage.setItem('jwt', jwt);
|
const usermodel = new userModel(id, roles, true);
|
||||||
localStorage.setItem('refresh', refresh);
|
// localStorage.setItem('jwt', jwt);
|
||||||
|
// localStorage.setItem('refresh', refresh);
|
||||||
this.setUser(usermodel);
|
this.setUser(usermodel);
|
||||||
return usermodel;
|
return usermodel;
|
||||||
});
|
});
|
||||||
|
@@ -8,6 +8,13 @@ export class roleModel {
|
|||||||
public permissions: permissionModel[] = [],
|
public permissions: permissionModel[] = [],
|
||||||
public baseRoleModel: roleModel | null = null
|
public baseRoleModel: roleModel | null = null
|
||||||
) {
|
) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
this.permissions = [];
|
||||||
|
for (const p of permissions) {
|
||||||
|
this.permissions.push(new permissionModel(p.id, '', ''));
|
||||||
|
}
|
||||||
if (baseRoleModel) {
|
if (baseRoleModel) {
|
||||||
this.permissions = baseRoleModel.permissions.concat(this.permissions);
|
this.permissions = baseRoleModel.permissions.concat(this.permissions);
|
||||||
}
|
}
|
||||||
|
@@ -11,47 +11,59 @@ enum SigningMethods {
|
|||||||
Microsoft = 'microsoft',
|
Microsoft = 'microsoft',
|
||||||
}
|
}
|
||||||
|
|
||||||
class userModel extends personModel {
|
class userModel {
|
||||||
constructor(
|
constructor(
|
||||||
public override id: string,
|
public id: string,
|
||||||
public email: string,
|
|
||||||
public password: string,
|
|
||||||
public override name: string,
|
|
||||||
public role: roleModel[],
|
public role: roleModel[],
|
||||||
public createdAt: Date,
|
public isLoggedIn: boolean
|
||||||
public updatedAt: Date,
|
|
||||||
public isLoggedIn: boolean,
|
|
||||||
public preferredSigningMethod: SigningMethods = SigningMethods.Password
|
|
||||||
) {
|
) {
|
||||||
super({
|
this.id = id;
|
||||||
id,
|
for (const r of role) {
|
||||||
name,
|
this.role.push(new roleModel(r.id, '', '', r.permissions, null));
|
||||||
profilePicture: null,
|
}
|
||||||
avatar: null,
|
this.isLoggedIn = isLoggedIn;
|
||||||
socialMedia: null,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// constructor(
|
||||||
|
// public override id: string,
|
||||||
|
// public email: string,
|
||||||
|
// public password: string,
|
||||||
|
// public override name: string,
|
||||||
|
// public role: roleModel[],
|
||||||
|
// public createdAt: Date,
|
||||||
|
// public updatedAt: Date,
|
||||||
|
// public isLoggedIn: boolean,
|
||||||
|
// public preferredSigningMethod: SigningMethods = SigningMethods.Password
|
||||||
|
// ) {
|
||||||
|
// super({
|
||||||
|
// id,
|
||||||
|
// name,
|
||||||
|
// profilePicture: null,
|
||||||
|
// avatar: null,
|
||||||
|
// socialMedia: null,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
get isAdmin(): boolean {
|
get isAdmin(): boolean {
|
||||||
return this.role.some((role) => role.isAdmin);
|
return this.role.some((r) => r.isAdmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isContentManager(): boolean {
|
get isContentManager(): boolean {
|
||||||
return this.role.some((role) => role.isContentManager);
|
return this.role.some((r) => r.isContentManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isUser(): boolean {
|
get isUser(): boolean {
|
||||||
return this.role.some((role) => role.isUser);
|
return this.role.some((r) => r.isUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly DefaultUser: userModel = new userModel(
|
public static readonly DefaultUser: userModel = new userModel(
|
||||||
'0',
|
'0',
|
||||||
'default@example.com',
|
// 'default@example.com',
|
||||||
'',
|
// '',
|
||||||
'Default User',
|
// 'Default User',
|
||||||
[roleModel.UserRole],
|
[roleModel.UserRole],
|
||||||
new Date(),
|
// new Date(),
|
||||||
new Date(),
|
// new Date(),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user