Files
Swarm/DysonNetwork.Pass/Features/Auth/Services/AccountService.cs

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