182 lines
5.7 KiB
C#
182 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using DysonNetwork.Common.Models;
|
|
using DysonNetwork.Pass.Data;
|
|
using DysonNetwork.Pass.Features.Auth.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NodaTime;
|
|
using Account = DysonNetwork.Common.Models.Account;
|
|
using AuthTokens = DysonNetwork.Common.Models.AuthTokens;
|
|
|
|
namespace DysonNetwork.Pass.Features.Auth.Services;
|
|
|
|
public class AccountService : IAccountService
|
|
{
|
|
private readonly PassDatabase _db;
|
|
private readonly IClock _clock;
|
|
|
|
public AccountService(PassDatabase db, IClock clock)
|
|
{
|
|
_db = db;
|
|
_clock = clock;
|
|
}
|
|
|
|
public async Task<Account> CreateAccount(Common.Models.OidcUserInfo userInfo)
|
|
{
|
|
if (string.IsNullOrEmpty(userInfo.Email))
|
|
throw new ArgumentException("Email is required for account creation", nameof(userInfo));
|
|
|
|
var now = _clock.GetCurrentInstant();
|
|
var account = new Models.Account
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Email = userInfo.Email,
|
|
Name = userInfo.Name ?? userInfo.Email.Split('@')[0],
|
|
CreatedAt = now,
|
|
UpdatedAt = now,
|
|
Status = "Active"
|
|
};
|
|
|
|
_db.Accounts.Add(account);
|
|
await _db.SaveChangesAsync();
|
|
|
|
return new Account
|
|
{
|
|
Id = account.Id.ToString(),
|
|
Email = account.Email,
|
|
Name = account.Name,
|
|
CreatedAt = account.CreatedAt,
|
|
UpdatedAt = account.UpdatedAt,
|
|
Status = account.Status
|
|
};
|
|
}
|
|
|
|
public async Task<Account?> FindByEmailAsync(string email)
|
|
{
|
|
if (string.IsNullOrEmpty(email))
|
|
return null;
|
|
|
|
var account = await _db.Accounts
|
|
.FirstOrDefaultAsync(a => a.Email == email);
|
|
|
|
if (account == null)
|
|
return null;
|
|
|
|
return new Account
|
|
{
|
|
Id = account.Id.ToString(),
|
|
Email = account.Email,
|
|
Name = account.Name,
|
|
CreatedAt = account.CreatedAt,
|
|
UpdatedAt = account.UpdatedAt,
|
|
Status = account.Status
|
|
};
|
|
}
|
|
|
|
public async Task<Account?> FindByIdAsync(string accountId)
|
|
{
|
|
if (string.IsNullOrEmpty(accountId) || !Guid.TryParse(accountId, out var id))
|
|
return null;
|
|
|
|
var account = await _db.Accounts
|
|
.FirstOrDefaultAsync(a => a.Id == id);
|
|
|
|
if (account == null)
|
|
return null;
|
|
|
|
return new Account
|
|
{
|
|
Id = account.Id.ToString(),
|
|
Email = account.Email,
|
|
Name = account.Name,
|
|
CreatedAt = account.CreatedAt,
|
|
UpdatedAt = account.UpdatedAt,
|
|
Status = account.Status
|
|
};
|
|
}
|
|
|
|
public async Task UpdateAccount(Account account)
|
|
{
|
|
if (!Guid.TryParse(account.Id, out var id))
|
|
throw new ArgumentException("Invalid account ID format", nameof(account));
|
|
|
|
var existingAccount = await _db.Accounts.FindAsync(id);
|
|
if (existingAccount == null)
|
|
throw new InvalidOperationException($"Account with ID {account.Id} not found");
|
|
|
|
existingAccount.Name = account.Name;
|
|
existingAccount.Email = account.Email;
|
|
existingAccount.UpdatedAt = _clock.GetCurrentInstant();
|
|
existingAccount.Status = account.Status;
|
|
|
|
_db.Accounts.Update(existingAccount);
|
|
await _db.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task<Account> FindOrCreateAccountAsync(Common.Models.OidcUserInfo userInfo, string provider)
|
|
{
|
|
if (string.IsNullOrEmpty(userInfo.Email))
|
|
throw new ArgumentException("Email is required for account creation", nameof(userInfo));
|
|
|
|
// Check if account exists by email
|
|
var account = await FindByEmailAsync(userInfo.Email);
|
|
if (account != null)
|
|
return account;
|
|
|
|
// Create new account if not found
|
|
return await CreateAccount(userInfo);
|
|
}
|
|
|
|
public async Task<Account?> GetAccountByIdAsync(Guid accountId)
|
|
{
|
|
var account = await _db.Accounts
|
|
.FirstOrDefaultAsync(a => a.Id == accountId);
|
|
|
|
if (account == null)
|
|
return null;
|
|
|
|
return new Account
|
|
{
|
|
Id = account.Id.ToString(),
|
|
Email = account.Email,
|
|
Name = account.Name,
|
|
CreatedAt = account.CreatedAt,
|
|
UpdatedAt = account.UpdatedAt,
|
|
Status = account.Status
|
|
};
|
|
}
|
|
|
|
public async Task<AuthTokens> GenerateAuthTokensAsync(Account account, string sessionId)
|
|
{
|
|
if (!Guid.TryParse(sessionId, out var sessionGuid))
|
|
throw new ArgumentException("Invalid session ID format", nameof(sessionId));
|
|
|
|
var now = _clock.GetCurrentInstant();
|
|
var accessTokenLifetime = Duration.FromHours(1);
|
|
var accessTokenExpiry = now.Plus(accessTokenLifetime);
|
|
|
|
// In a real implementation, you would generate proper JWT tokens here
|
|
// This is a simplified version for demonstration
|
|
var accessToken = $"access_token_{Guid.NewGuid()}";
|
|
var refreshToken = $"refresh_token_{Guid.NewGuid()}";
|
|
|
|
// Create or update the session
|
|
var session = await _db.AuthSessions.FindAsync(sessionGuid);
|
|
if (session != null)
|
|
{
|
|
session.UpdateTokens(accessToken, refreshToken, accessTokenLifetime);
|
|
_db.AuthSessions.Update(session);
|
|
await _db.SaveChangesAsync();
|
|
}
|
|
|
|
return new AuthTokens
|
|
{
|
|
AccessToken = accessToken,
|
|
RefreshToken = refreshToken,
|
|
ExpiresIn = (int)accessTokenLifetime.TotalSeconds,
|
|
TokenType = "Bearer"
|
|
};
|
|
}
|
|
}
|