From 0af74ec2782103f2fcb9f6d88b816c07d8a60bab Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Sun, 21 Sep 2025 23:57:37 +0300 Subject: [PATCH] Add LastLogin and CreatedAt to User --- Azaion.Common/Entities/User.cs | 2 ++ Azaion.Services/AuthService.cs | 2 +- Azaion.Services/UserService.cs | 14 +++++++++++++- Azaion.Test/UserServiceTest.cs | 25 +++++++++++++++++++++++++ env/api/02-nginx-docker-registry.sh | 2 ++ env/db/02_structure.sql | 4 +++- env/db/03_add_timestamp_columns.sql | 3 +++ 7 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 Azaion.Test/UserServiceTest.cs create mode 100644 env/db/03_add_timestamp_columns.sql diff --git a/Azaion.Common/Entities/User.cs b/Azaion.Common/Entities/User.cs index f4a098d..195a2bf 100644 --- a/Azaion.Common/Entities/User.cs +++ b/Azaion.Common/Entities/User.cs @@ -8,6 +8,8 @@ public class User public string? Hardware { get; set; } public RoleEnum Role { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? LastLogin { get; set; } public UserConfig? UserConfig { get; set; } = null!; public static string GetCacheKey(string email) => diff --git a/Azaion.Services/AuthService.cs b/Azaion.Services/AuthService.cs index 157f973..fb6177b 100644 --- a/Azaion.Services/AuthService.cs +++ b/Azaion.Services/AuthService.cs @@ -11,7 +11,7 @@ namespace Azaion.Services; public interface IAuthService { - Task GetCurrentUser(); + Task GetCurrentUser(); string CreateToken(User user); } diff --git a/Azaion.Services/UserService.cs b/Azaion.Services/UserService.cs index b3b445b..8de41f0 100644 --- a/Azaion.Services/UserService.cs +++ b/Azaion.Services/UserService.cs @@ -34,7 +34,8 @@ public class UserService(IDbFactory dbFactory, ICache cache) : IUserService Id = Guid.NewGuid(), Email = request.Email, PasswordHash = request.Password.ToHash(), - Role = request.Role + Role = request.Role, + CreatedAt = DateTime.UtcNow }, token: ct); }); } @@ -108,12 +109,23 @@ public class UserService(IDbFactory dbFactory, ICache cache) : IUserService { await UpdateHardware(user.Email, hardware, ct); cache.Invalidate(User.GetCacheKey(user.Email)); + await UpdateLastLoginDate(user, ct); return requestHWHash; } var userHWHash = Security.GetHWHash(user.Hardware); if (userHWHash != requestHWHash) throw new BusinessException(ExceptionEnum.HardwareIdMismatch); + await UpdateLastLoginDate(user, ct); return userHWHash; } + + private async Task UpdateLastLoginDate(User user, CancellationToken ct = default) + { + await dbFactory.Run(async db => + await db.Users.UpdateAsync(x => x.Email == user.Email, u => new User + { + LastLogin = DateTime.UtcNow + }, ct)); + } } diff --git a/Azaion.Test/UserServiceTest.cs b/Azaion.Test/UserServiceTest.cs new file mode 100644 index 0000000..01a59e4 --- /dev/null +++ b/Azaion.Test/UserServiceTest.cs @@ -0,0 +1,25 @@ +using Azaion.Common.Configs; +using Azaion.Common.Database; +using Azaion.Services; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Azaion.Test; + +public class UserServiceTest +{ + [Fact] + public async Task CheckHardwareHashTest() + { + var dbFactory = new DbFactory(new OptionsWrapper(new ConnectionStrings + { + AzaionDb = "Host=188.245.120.247;Port=4312;Database=azaion;Username=azaion_reader;Password=A@1n_zxre@d!only@$Az", + AzaionDbAdmin = "Host=188.245.120.247;Port=4312;Database=azaion;Username=azaion_admin;Password=Az@1on_Oddmin$$@r" + })); + var userService = new UserService(dbFactory, new MemoryCache()); + var user = await userService.GetByEmail("spielberg@azaion.com"); + + var res = await userService.CheckHardwareHash(user, + "CPU: AMD Ryzen 9 3900XT 12-Core Processor. GPU: Microsoft Remote Display Adapter. Memory: 67037080. DriveSerial: PHMB746301G6480DGN _00000001."); + } +} \ No newline at end of file diff --git a/env/api/02-nginx-docker-registry.sh b/env/api/02-nginx-docker-registry.sh index e4a6ced..9cad26d 100644 --- a/env/api/02-nginx-docker-registry.sh +++ b/env/api/02-nginx-docker-registry.sh @@ -20,6 +20,7 @@ tee -a docker.azaion.com << END server { listen 443 ssl; server_name docker.azaion.com; + client_max_body_size 900M; ssl_certificate /etc/letsencrypt/live/docker.azaion.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/docker.azaion.com/privkey.pem; @@ -39,6 +40,7 @@ server { server { listen 80; server_name docker.azaion.com; + client_max_body_size 900M; location / { auth_basic "Registry"; diff --git a/env/db/02_structure.sql b/env/db/02_structure.sql index 5e392a4..b5e3736 100644 --- a/env/db/02_structure.sql +++ b/env/db/02_structure.sql @@ -8,7 +8,9 @@ create table users hardware text null, hardware_hash varchar(120) null, role varchar(20) not null, - user_config varchar(512) null + user_config varchar(512) null, + created_at timestamp not null default now(), + last_login timestamp null ); grant select, insert, update, delete on public.users to azaion_admin; grant select on table public.users to azaion_reader; diff --git a/env/db/03_add_timestamp_columns.sql b/env/db/03_add_timestamp_columns.sql new file mode 100644 index 0000000..ad2071d --- /dev/null +++ b/env/db/03_add_timestamp_columns.sql @@ -0,0 +1,3 @@ +ALTER TABLE public.users +ADD COLUMN IF NOT EXISTS created_at timestamp not null default now(), +ADD COLUMN IF NOT EXISTS last_login timestamp null; \ No newline at end of file