chore: moving towards agentic development
Some checks failed
Backend CI/CD / build_and_deploy (push) Has been cancelled
Frontend CI/CD / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-04-24 21:12:26 -04:00
parent df3e602015
commit b6eb692c27
179 changed files with 2880 additions and 866 deletions

View File

@@ -0,0 +1,43 @@
using System.Security.Claims;
using Socialize.Infrastructure.Security;
using Socialize.Modules.Identity.Configuration;
using Socialize.Modules.Identity.Contracts;
using Socialize.Modules.Identity.Data;
using Microsoft.Extensions.Options;
namespace Socialize.Modules.Identity.Services;
public sealed class AccessTokenFactory(
UserManager userManager,
IOptionsSnapshot<JwtOptions> jwtOptions)
{
public async Task<string> CreateAsync(User user)
{
IList<string> roles = await userManager.GetRolesAsync(user);
IList<Claim> claims = await userManager.GetClaimsAsync(user);
string persona = roles.Contains(KnownRoles.Manager, StringComparer.Ordinal)
? KnownRoles.Manager
: roles.Contains(KnownRoles.Client, StringComparer.Ordinal)
? KnownRoles.Client
: roles.Contains(KnownRoles.Provider, StringComparer.Ordinal)
? KnownRoles.Provider
: KnownRoles.WorkspaceMember;
List<Claim> tokenClaims = [.. claims, new Claim(KnownClaims.Persona, persona)];
return JwtTokenHelper.GenerateJwtToken(
jwtOptions.Value.Lifetime,
jwtOptions.Value.Issuer,
jwtOptions.Value.Audience,
jwtOptions.Value.Key,
user.Id.ToString(),
user.Email ?? string.Empty,
user.Alias,
user.Firstname ?? string.Empty,
user.Lastname ?? string.Empty,
user.PortraitUrl,
roles,
tokenClaims);
}
}

View File

@@ -0,0 +1,61 @@
using System.Web;
using Socialize.Infrastructure.Configuration;
using Socialize.Infrastructure.Emailer.Contracts;
using Socialize.Modules.Identity.Data;
using Microsoft.Extensions.Options;
namespace Socialize.Modules.Identity.Services;
[PublicAPI]
public sealed class EmailVerificationService(
IOptionsSnapshot<WebsiteOptions> options,
UserManager userManager,
IEmailSender emailSender)
{
public async Task SendVerificationEmailAsync(
User user)
{
// Generate email confirmation token
string token = await userManager.GenerateEmailConfirmationTokenAsync(user);
string encodedToken = HttpUtility.UrlEncode(token);
string verificationLink = $"{options.Value.FrontendBaseUrl}/verify-email?userId={user.Id}&token={encodedToken}";
// Send verification email
await emailSender.SendEmailAsync(
user.Email!,
"Verify your email address",
$"""
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; color: #333;">
<h1 style="color: #2c3e50; margin-bottom: 20px;">Welcome to Socialize!</h1>
<p style="font-size: 16px; line-height: 1.5; margin-bottom: 25px;">
Please verify your email address by clicking the button below:
</p>
<div style="text-align: center; margin: 30px 0;">
<a href='{verificationLink}'
style="background-color: #3498db;
color: white;
text-decoration: none;
padding: 12px 24px;
border-radius: 4px;
font-weight: bold;
display: inline-block;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
Verify Email Address
</a>
</div>
<p style="font-size: 14px; color: #7f8c8d; margin-top: 30px;">
If you did not request this, please ignore this email.
</p>
<p style="font-size: 14px; color: #7f8c8d; margin-top: 20px;">
If the button doesn't work, you can copy and paste this link into your browser:
<br>
<a href='{verificationLink}' style="color: #3498db; word-break: break-all;">{verificationLink}</a>
</p>
</div>
""");
}
}

View File

@@ -0,0 +1,21 @@
using Socialize.Modules.Identity.Contracts;
using Socialize.Modules.Identity.Data;
namespace Socialize.Modules.Identity.Services;
public sealed class UserLookup(
UserManager userManager)
: IUserLookup
{
public async Task<UserReference?> GetUserAsync(Guid userId, CancellationToken cancellationToken = default)
{
User? user = await userManager.FindByIdAsync(userId.ToString());
return user is null
? null
: new UserReference(
user.Id,
user.Fullname,
user.PortraitUrl);
}
}