d4fee8d1d7
Build backend images / build content-svc (push) Failing after 1m59s
Build backend images / build file-svc (push) Failing after 3m18s
Build backend images / build gateway (push) Failing after 3m28s
Build backend images / build identity-svc (push) Failing after 2m1s
Build backend images / build notification-svc (push) Failing after 4m45s
Build backend images / build render-svc (push) Failing after 5m18s
Build backend images / build studio-svc (push) Failing after 2m12s
Navigation: - UserMenu (avatar + role-aware dropdown: Dashboard, Admin Panel for admins, Profile, Sign out) replaces Sign In/Try Free when logged in (desktop + mobile). - Real avatars in dashboard sidebar + a new admin-shell profile section. - Shared Avatar primitive (image with initials fallback). SiteChrome excludes /admin. Profile (data-collection surface for future AI video generation): - SettingsProfile rebuilt: avatar upload + slogan, about, company, website, country, national code, birthdate, gender. No resume builder (per scope change). - /api/profile forwards all fields; new user-scoped /api/profile/upload (avatar → MinIO via file-svc, sets avatar). Identity UpdateUserRequest/UserResponse widened (country/national/method); no DB migration (columns already exist). - fa+en strings; verified GET/PATCH round-trip + logged-in SSR render. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
132 lines
5.1 KiB
C#
132 lines
5.1 KiB
C#
using FlatRender.IdentitySvc.Application.Services.Interfaces;
|
|
using FlatRender.IdentitySvc.Domain.Enums;
|
|
using FlatRender.IdentitySvc.Infrastructure.Data;
|
|
using FlatRender.IdentitySvc.Models.Requests;
|
|
using FlatRender.IdentitySvc.Models.Responses;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace FlatRender.IdentitySvc.Application.Services;
|
|
|
|
public class UserService(IdentityDbContext db) : IUserService
|
|
{
|
|
public async Task<UserResponse> GetMeAsync(Guid userId)
|
|
{
|
|
var user = await db.Users.FindAsync(userId)
|
|
?? throw new KeyNotFoundException("User not found");
|
|
return AuthService.MapUserResponse(user);
|
|
}
|
|
|
|
public async Task<UserResponse> UpdateMeAsync(Guid userId, UpdateUserRequest request)
|
|
{
|
|
var user = await db.Users.FindAsync(userId)
|
|
?? throw new KeyNotFoundException("User not found");
|
|
|
|
if (request.FullName != null) user.FullName = request.FullName;
|
|
if (request.Slogan != null) user.Slogan = request.Slogan;
|
|
if (request.AboutMe != null) user.AboutMe = request.AboutMe;
|
|
if (request.CompanyName != null) user.CompanyName = request.CompanyName;
|
|
if (request.WebsiteName != null) user.WebsiteName = request.WebsiteName;
|
|
if (request.BirthDate.HasValue) user.BirthDate = request.BirthDate;
|
|
if (request.Gender != null && Enum.TryParse<GenderKind>(request.Gender, true, out var gender))
|
|
user.Gender = gender;
|
|
if (request.EmailTellMe.HasValue) user.EmailTellMe = request.EmailTellMe.Value;
|
|
if (request.SmsTellMe.HasValue) user.SmsTellMe = request.SmsTellMe.Value;
|
|
if (request.PushTellMe.HasValue) user.PushTellMe = request.PushTellMe.Value;
|
|
if (request.TelegramTellMe.HasValue) user.TelegramTellMe = request.TelegramTellMe.Value;
|
|
if (request.CountryCode != null) user.CountryCode = request.CountryCode;
|
|
if (request.NationalCode != null) user.NationalCode = request.NationalCode;
|
|
if (request.MethodOfIntroduction != null) user.MethodOfIntroduction = request.MethodOfIntroduction;
|
|
|
|
user.UpdatedAt = DateTime.UtcNow;
|
|
await db.SaveChangesAsync();
|
|
return AuthService.MapUserResponse(user);
|
|
}
|
|
|
|
public async Task<BalanceResponse> GetBalanceAsync(Guid userId)
|
|
{
|
|
var user = await db.Users.FindAsync(userId)
|
|
?? throw new KeyNotFoundException("User not found");
|
|
return new BalanceResponse(
|
|
user.BalanceMinor,
|
|
user.AffiliateBalanceMinor,
|
|
"IRR",
|
|
user.DailyRemainRenderCount,
|
|
user.ParallelRenderingCeiling
|
|
);
|
|
}
|
|
|
|
public async Task UpdateAvatarAsync(Guid userId, Guid? avatarId, string? avatarUrl)
|
|
{
|
|
var user = await db.Users.FindAsync(userId)
|
|
?? throw new KeyNotFoundException("User not found");
|
|
|
|
if (avatarId.HasValue)
|
|
{
|
|
var avatar = await db.Avatars.FindAsync(avatarId.Value);
|
|
if (avatar != null) user.AvatarUrl = avatar.Url;
|
|
}
|
|
else if (!string.IsNullOrEmpty(avatarUrl))
|
|
{
|
|
user.AvatarUrl = avatarUrl;
|
|
}
|
|
|
|
user.UpdatedAt = DateTime.UtcNow;
|
|
await db.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task<UserResponse> GetByIdAsync(Guid userId)
|
|
{
|
|
var user = await db.Users.FindAsync(userId)
|
|
?? throw new KeyNotFoundException("User not found");
|
|
return AuthService.MapUserResponse(user);
|
|
}
|
|
|
|
public async Task<PagedResponse<UserResponse>> SearchAsync(string? q, Guid? tenantId, int page, int pageSize)
|
|
{
|
|
var query = db.Users.Where(u => u.DeletedAt == null);
|
|
|
|
if (tenantId.HasValue)
|
|
query = query.Where(u => u.TenantId == tenantId.Value);
|
|
|
|
if (!string.IsNullOrWhiteSpace(q))
|
|
query = query.Where(u =>
|
|
(u.Email != null && u.Email.Contains(q)) ||
|
|
(u.FullName != null && EF.Functions.ILike(u.FullName, $"%{q}%")) ||
|
|
(u.PhoneNumber != null && u.PhoneNumber.Contains(q)));
|
|
|
|
var total = await query.LongCountAsync();
|
|
var users = await query
|
|
.OrderByDescending(u => u.RegisterDate)
|
|
.Skip((page - 1) * pageSize)
|
|
.Take(pageSize)
|
|
.ToListAsync();
|
|
|
|
return new PagedResponse<UserResponse>(
|
|
users.Select(AuthService.MapUserResponse).ToList(),
|
|
new PaginationMeta(page, pageSize, total, total > (long)page * pageSize)
|
|
);
|
|
}
|
|
|
|
public async Task BanAsync(Guid userId, string reason, DateTime? unblockDate)
|
|
{
|
|
var user = await db.Users.FindAsync(userId)
|
|
?? throw new KeyNotFoundException("User not found");
|
|
user.BanAccount = true;
|
|
user.BanReason = reason;
|
|
user.UnblockDate = unblockDate;
|
|
user.UpdatedAt = DateTime.UtcNow;
|
|
await db.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task UnbanAsync(Guid userId)
|
|
{
|
|
var user = await db.Users.FindAsync(userId)
|
|
?? throw new KeyNotFoundException("User not found");
|
|
user.BanAccount = false;
|
|
user.BanReason = null;
|
|
user.UnblockDate = null;
|
|
user.UpdatedAt = DateTime.UtcNow;
|
|
await db.SaveChangesAsync();
|
|
}
|
|
}
|