This commit is contained in:
2025-08-28 16:01:55 +02:00
parent 68b74284c7
commit c7a94893a2
63 changed files with 633 additions and 200 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -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"
} }

View File

@@ -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; } = [];
} }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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" };

View File

@@ -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;

View File

@@ -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;

View File

@@ -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",
[ [

View File

@@ -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());

View File

@@ -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();

View File

@@ -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;

View File

@@ -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"
} }
} }

View File

@@ -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>

View File

@@ -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

View 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
}
}

View File

@@ -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);

View File

@@ -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";
} }

View File

@@ -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

View File

@@ -1,4 +1,4 @@
using DependencyInjector.Lifetimes; using DependencyInjector.Abstractions.Lifetimes;
namespace back.persistance.blob; namespace back.persistance.blob;

View File

@@ -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);
} }

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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;

View 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();
}
}

View File

@@ -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;

View File

@@ -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;

View 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();
}
}

View File

@@ -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
{ {

View File

@@ -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
// ); );
// } }
//} }

View File

@@ -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" }
// ); );
// } }
//} }

View File

@@ -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
); // );
} // }
} //}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
} }
} }

View File

@@ -1,4 +1,4 @@
using DependencyInjector.Lifetimes; using DependencyInjector.Abstractions.Lifetimes;
namespace back.services.engine.Crypto; namespace back.services.engine.Crypto;

View File

@@ -1,4 +1,4 @@
using DependencyInjector.Lifetimes; using DependencyInjector.Abstractions.Lifetimes;
namespace back.services.engine.ImageResizer; namespace back.services.engine.ImageResizer;

View File

@@ -1,4 +1,4 @@
using DependencyInjector.Lifetimes; using DependencyInjector.Abstractions.Lifetimes;
namespace back.services.engine.PasswordGenerator; namespace back.services.engine.PasswordGenerator;

View File

@@ -1,4 +1,4 @@
using DependencyInjector.Lifetimes; using DependencyInjector.Abstractions.Lifetimes;
namespace back.services.engine.SystemUser; namespace back.services.engine.SystemUser;

View File

@@ -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);
}); });

View File

@@ -1,4 +1,4 @@
using DependencyInjector.Lifetimes; using DependencyInjector.Abstractions.Lifetimes;
namespace back.services.engine.mailing; namespace back.services.engine.mailing;

View File

@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Mvc;
namespace Presentation.Controllers;
public class AuthController : Controller
{
}

View File

@@ -0,0 +1,6 @@
namespace Presentation.Infraestructura.Responses;
public sealed class ExecutionError(string message)
{
public string Message { get; set; } = message;
}

View 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
};
}

View File

@@ -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;
}

View 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>

View 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();
}
}
}
}

View 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"
}
}
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@@ -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

View File

@@ -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 {}
}

View File

@@ -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

View File

@@ -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 {}
}

View File

@@ -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',

View File

@@ -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

View File

@@ -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 {}
}

View File

@@ -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;
}); });

View File

@@ -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);
} }

View File

@@ -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
); );
} }