♻️ Finish centerlizing the data models

This commit is contained in:
2025-09-27 15:14:05 +08:00
parent e70d8371f8
commit 9ce31c4dd8
167 changed files with 780 additions and 42880 deletions

View File

@@ -4,6 +4,7 @@ using DysonNetwork.Pass.Credit;
using DysonNetwork.Pass.Wallet;
using DysonNetwork.Shared.Error;
using DysonNetwork.Shared.GeoIp;
using DysonNetwork.Shared.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NodaTime;
@@ -23,9 +24,9 @@ public class AccountController(
) : ControllerBase
{
[HttpGet("{name}")]
[ProducesResponseType<Account>(StatusCodes.Status200OK)]
[ProducesResponseType<SnAccount>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Account?>> GetByName(string name)
public async Task<ActionResult<SnAccount?>> GetByName(string name)
{
var account = await db.Accounts
.Include(e => e.Badges)
@@ -42,9 +43,9 @@ public class AccountController(
}
[HttpGet("{name}/badges")]
[ProducesResponseType<List<AccountBadge>>(StatusCodes.Status200OK)]
[ProducesResponseType<List<SnAccountBadge>>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<List<AccountBadge>>> GetBadgesByName(string name)
public async Task<ActionResult<List<SnAccountBadge>>> GetBadgesByName(string name)
{
var account = await db.Accounts
.Include(e => e.Badges)
@@ -103,9 +104,9 @@ public class AccountController(
}
[HttpPost]
[ProducesResponseType<Account>(StatusCodes.Status200OK)]
[ProducesResponseType<SnAccount>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Account>> CreateAccount([FromBody] AccountCreateRequest request)
public async Task<ActionResult<SnAccount>> CreateAccount([FromBody] AccountCreateRequest request)
{
if (!await auth.ValidateCaptcha(request.CaptchaToken))
return BadRequest(ApiError.Validation(new Dictionary<string, string[]>
@@ -199,7 +200,7 @@ public class AccountController(
}
[HttpGet("{name}/statuses")]
public async Task<ActionResult<Status>> GetOtherStatus(string name)
public async Task<ActionResult<SnAccountStatus>> GetOtherStatus(string name)
{
var account = await db.Accounts.FirstOrDefaultAsync(a => a.Name == name);
if (account is null)
@@ -254,7 +255,7 @@ public class AccountController(
}
[HttpGet("search")]
public async Task<List<Account>> Search([FromQuery] string query, [FromQuery] int take = 20)
public async Task<List<SnAccount>> Search([FromQuery] string query, [FromQuery] int take = 20)
{
if (string.IsNullOrWhiteSpace(query))
return [];

View File

@@ -28,11 +28,11 @@ public class AccountCurrentController(
) : ControllerBase
{
[HttpGet]
[ProducesResponseType<Account>(StatusCodes.Status200OK)]
[ProducesResponseType<SnAccount>(StatusCodes.Status200OK)]
[ProducesResponseType<ApiError>(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<Account>> GetCurrentIdentity()
public async Task<ActionResult<SnAccount>> GetCurrentIdentity()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var userId = currentUser.Id;
var account = await db.Accounts
@@ -55,9 +55,9 @@ public class AccountCurrentController(
}
[HttpPatch]
public async Task<ActionResult<Account>> UpdateBasicInfo([FromBody] BasicInfoRequest request)
public async Task<ActionResult<SnAccount>> UpdateBasicInfo([FromBody] BasicInfoRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var account = await db.Accounts.FirstAsync(a => a.Id == currentUser.Id);
@@ -88,9 +88,9 @@ public class AccountCurrentController(
}
[HttpPatch("profile")]
public async Task<ActionResult<AccountProfile>> UpdateProfile([FromBody] ProfileRequest request)
public async Task<ActionResult<SnAccountProfile>> UpdateProfile([FromBody] ProfileRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var userId = currentUser.Id;
var profile = await db.AccountProfiles
@@ -163,7 +163,7 @@ public class AccountCurrentController(
[HttpDelete]
public async Task<ActionResult> RequestDeleteAccount()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -184,18 +184,18 @@ public class AccountCurrentController(
}
[HttpGet("statuses")]
public async Task<ActionResult<Status>> GetCurrentStatus()
public async Task<ActionResult<SnAccountStatus>> GetCurrentStatus()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var status = await events.GetStatus(currentUser.Id);
return Ok(status);
}
[HttpPatch("statuses")]
[RequiredPermission("global", "accounts.statuses.update")]
public async Task<ActionResult<Status>> UpdateStatus([FromBody] AccountController.StatusRequest request)
public async Task<ActionResult<SnAccountStatus>> UpdateStatus([FromBody] AccountController.StatusRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
if (request is { IsAutomated: true, AppIdentifier: not null })
return BadRequest("Automated status cannot be updated.");
@@ -227,9 +227,9 @@ public class AccountCurrentController(
[HttpPost("statuses")]
[RequiredPermission("global", "accounts.statuses.create")]
public async Task<ActionResult<Status>> CreateStatus([FromBody] AccountController.StatusRequest request)
public async Task<ActionResult<SnAccountStatus>> CreateStatus([FromBody] AccountController.StatusRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
if (request is { IsAutomated: true, AppIdentifier: not null })
{
@@ -261,7 +261,7 @@ public class AccountCurrentController(
return Ok(existingStatus); // Do not override manually set status with automated ones
}
var status = new Status
var status = new SnAccountStatus
{
AccountId = currentUser.Id,
Attitude = request.Attitude,
@@ -280,7 +280,7 @@ public class AccountCurrentController(
[HttpDelete("statuses")]
public async Task<ActionResult> DeleteStatus([FromQuery] string? app)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var now = SystemClock.Instance.GetCurrentInstant();
var queryable = db.AccountStatuses
@@ -301,9 +301,9 @@ public class AccountCurrentController(
}
[HttpGet("check-in")]
public async Task<ActionResult<CheckInResult>> GetCheckInResult()
public async Task<ActionResult<SnCheckInResult>> GetCheckInResult()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var userId = currentUser.Id;
var now = SystemClock.Instance.GetCurrentInstant();
@@ -323,12 +323,12 @@ public class AccountCurrentController(
}
[HttpPost("check-in")]
public async Task<ActionResult<CheckInResult>> DoCheckIn(
public async Task<ActionResult<SnCheckInResult>> DoCheckIn(
[FromBody] string? captchaToken,
[FromQuery] Instant? backdated = null
)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
if (backdated is null)
{
@@ -399,7 +399,7 @@ public class AccountCurrentController(
public async Task<ActionResult<List<DailyEventResponse>>> GetEventCalendar([FromQuery] int? month,
[FromQuery] int? year)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var currentDate = SystemClock.Instance.GetCurrentInstant().InUtc().Date;
month ??= currentDate.Month;
@@ -428,7 +428,7 @@ public class AccountCurrentController(
[FromQuery] int offset = 0
)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var query = db.ActionLogs
.Where(log => log.AccountId == currentUser.Id)
@@ -446,9 +446,9 @@ public class AccountCurrentController(
}
[HttpGet("factors")]
public async Task<ActionResult<List<AccountAuthFactor>>> GetAuthFactors()
public async Task<ActionResult<List<SnAccountAuthFactor>>> GetAuthFactors()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var factors = await db.AccountAuthFactors
.Include(f => f.Account)
@@ -460,15 +460,15 @@ public class AccountCurrentController(
public class AuthFactorRequest
{
public AccountAuthFactorType Type { get; set; }
public Shared.Models.AccountAuthFactorType Type { get; set; }
public string? Secret { get; set; }
}
[HttpPost("factors")]
[Authorize]
public async Task<ActionResult<AccountAuthFactor>> CreateAuthFactor([FromBody] AuthFactorRequest request)
public async Task<ActionResult<SnAccountAuthFactor>> CreateAuthFactor([FromBody] AuthFactorRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
if (await accounts.CheckAuthFactorExists(currentUser, request.Type))
return BadRequest(new ApiError
{
@@ -484,9 +484,9 @@ public class AccountCurrentController(
[HttpPost("factors/{id:guid}/enable")]
[Authorize]
public async Task<ActionResult<AccountAuthFactor>> EnableAuthFactor(Guid id, [FromBody] string? code)
public async Task<ActionResult<SnAccountAuthFactor>> EnableAuthFactor(Guid id, [FromBody] string? code)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var factor = await db.AccountAuthFactors
.Where(f => f.AccountId == currentUser.Id && f.Id == id)
@@ -513,9 +513,9 @@ public class AccountCurrentController(
[HttpPost("factors/{id:guid}/disable")]
[Authorize]
public async Task<ActionResult<AccountAuthFactor>> DisableAuthFactor(Guid id)
public async Task<ActionResult<SnAccountAuthFactor>> DisableAuthFactor(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var factor = await db.AccountAuthFactors
.Where(f => f.AccountId == currentUser.Id && f.Id == id)
@@ -535,9 +535,9 @@ public class AccountCurrentController(
[HttpDelete("factors/{id:guid}")]
[Authorize]
public async Task<ActionResult<AccountAuthFactor>> DeleteAuthFactor(Guid id)
public async Task<ActionResult<SnAccountAuthFactor>> DeleteAuthFactor(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var factor = await db.AccountAuthFactors
.Where(f => f.AccountId == currentUser.Id && f.Id == id)
@@ -559,7 +559,7 @@ public class AccountCurrentController(
[Authorize]
public async Task<ActionResult<List<SnAuthClientWithChallenge>>> GetDevices()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser ||
HttpContext.Items["CurrentSession"] is not SnAuthSession currentSession) return Unauthorized();
Response.Headers.Append("X-Auth-Session", currentSession.Id.ToString());
@@ -589,7 +589,7 @@ public class AccountCurrentController(
[FromQuery] int offset = 0
)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser ||
HttpContext.Items["CurrentSession"] is not SnAuthSession currentSession) return Unauthorized();
var query = db.AuthSessions
@@ -614,7 +614,7 @@ public class AccountCurrentController(
[Authorize]
public async Task<ActionResult<SnAuthSession>> DeleteSession(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -631,7 +631,7 @@ public class AccountCurrentController(
[Authorize]
public async Task<ActionResult<SnAuthSession>> DeleteDevice(string deviceId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -648,7 +648,7 @@ public class AccountCurrentController(
[Authorize]
public async Task<ActionResult<SnAuthSession>> DeleteCurrentSession()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser ||
HttpContext.Items["CurrentSession"] is not SnAuthSession currentSession) return Unauthorized();
try
@@ -666,7 +666,7 @@ public class AccountCurrentController(
[Authorize]
public async Task<ActionResult<SnAuthSession>> UpdateDeviceLabel(string deviceId, [FromBody] string label)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -683,7 +683,7 @@ public class AccountCurrentController(
[Authorize]
public async Task<ActionResult<SnAuthSession>> UpdateCurrentDeviceLabel([FromBody] string label)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser ||
HttpContext.Items["CurrentSession"] is not SnAuthSession currentSession) return Unauthorized();
var device = await db.AuthClients.FirstOrDefaultAsync(d => d.Id == currentSession.Challenge.ClientId);
@@ -702,9 +702,9 @@ public class AccountCurrentController(
[HttpGet("contacts")]
[Authorize]
public async Task<ActionResult<List<AccountContact>>> GetContacts()
public async Task<ActionResult<List<SnAccountContact>>> GetContacts()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var contacts = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id)
@@ -715,15 +715,15 @@ public class AccountCurrentController(
public class AccountContactRequest
{
[Required] public AccountContactType Type { get; set; }
[Required] public Shared.Models.AccountContactType Type { get; set; }
[Required] public string Content { get; set; } = null!;
}
[HttpPost("contacts")]
[Authorize]
public async Task<ActionResult<AccountContact>> CreateContact([FromBody] AccountContactRequest request)
public async Task<ActionResult<SnAccountContact>> CreateContact([FromBody] AccountContactRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -738,9 +738,9 @@ public class AccountCurrentController(
[HttpPost("contacts/{id:guid}/verify")]
[Authorize]
public async Task<ActionResult<AccountContact>> VerifyContact(Guid id)
public async Task<ActionResult<SnAccountContact>> VerifyContact(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
@@ -760,9 +760,9 @@ public class AccountCurrentController(
[HttpPost("contacts/{id:guid}/primary")]
[Authorize]
public async Task<ActionResult<AccountContact>> SetPrimaryContact(Guid id)
public async Task<ActionResult<SnAccountContact>> SetPrimaryContact(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
@@ -782,9 +782,9 @@ public class AccountCurrentController(
[HttpPost("contacts/{id:guid}/public")]
[Authorize]
public async Task<ActionResult<AccountContact>> SetPublicContact(Guid id)
public async Task<ActionResult<SnAccountContact>> SetPublicContact(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
@@ -804,9 +804,9 @@ public class AccountCurrentController(
[HttpDelete("contacts/{id:guid}/public")]
[Authorize]
public async Task<ActionResult<AccountContact>> UnsetPublicContact(Guid id)
public async Task<ActionResult<SnAccountContact>> UnsetPublicContact(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
@@ -826,9 +826,9 @@ public class AccountCurrentController(
[HttpDelete("contacts/{id:guid}")]
[Authorize]
public async Task<ActionResult<AccountContact>> DeleteContact(Guid id)
public async Task<ActionResult<SnAccountContact>> DeleteContact(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var contact = await db.AccountContacts
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
@@ -847,11 +847,11 @@ public class AccountCurrentController(
}
[HttpGet("badges")]
[ProducesResponseType<List<AccountBadge>>(StatusCodes.Status200OK)]
[ProducesResponseType<List<SnAccountBadge>>(StatusCodes.Status200OK)]
[Authorize]
public async Task<ActionResult<List<AccountBadge>>> GetBadges()
public async Task<ActionResult<List<SnAccountBadge>>> GetBadges()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var badges = await db.Badges
.Where(b => b.AccountId == currentUser.Id)
@@ -861,9 +861,9 @@ public class AccountCurrentController(
[HttpPost("badges/{id:guid}/active")]
[Authorize]
public async Task<ActionResult<AccountBadge>> ActivateBadge(Guid id)
public async Task<ActionResult<SnAccountBadge>> ActivateBadge(Guid id)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -878,12 +878,12 @@ public class AccountCurrentController(
[HttpGet("leveling")]
[Authorize]
public async Task<ActionResult<ExperienceRecord>> GetLevelingHistory(
public async Task<ActionResult<SnExperienceRecord>> GetLevelingHistory(
[FromQuery] int take = 20,
[FromQuery] int offset = 0
)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var queryable = db.ExperienceRecords
.Where(r => r.AccountId == currentUser.Id)
@@ -903,7 +903,7 @@ public class AccountCurrentController(
[HttpGet("credits")]
public async Task<ActionResult<bool>> GetSocialCredit()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var credit = await creditService.GetSocialCredit(currentUser.Id);
return Ok(credit);
@@ -915,7 +915,7 @@ public class AccountCurrentController(
[FromQuery] int offset = 0
)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var queryable = db.SocialCreditRecords
.Where(r => r.AccountId == currentUser.Id)

View File

@@ -37,10 +37,10 @@ public class AccountEventService(
cache.RemoveAsync(cacheKey);
}
public async Task<Status> GetStatus(Guid userId)
public async Task<SnAccountStatus> GetStatus(Guid userId)
{
var cacheKey = $"{StatusCacheKey}{userId}";
var cachedStatus = await cache.GetAsync<Status>(cacheKey);
var cachedStatus = await cache.GetAsync<SnAccountStatus>(cacheKey);
if (cachedStatus is not null)
{
cachedStatus!.IsOnline = !cachedStatus.IsInvisible && await GetAccountIsConnected(userId);
@@ -64,9 +64,9 @@ public class AccountEventService(
if (isOnline)
{
return new Status
return new SnAccountStatus
{
Attitude = StatusAttitude.Neutral,
Attitude = Shared.Models.StatusAttitude.Neutral,
IsOnline = true,
IsCustomized = false,
Label = "Online",
@@ -74,9 +74,9 @@ public class AccountEventService(
};
}
return new Status
return new SnAccountStatus
{
Attitude = StatusAttitude.Neutral,
Attitude = Shared.Models.StatusAttitude.Neutral,
IsOnline = false,
IsCustomized = false,
Label = "Offline",
@@ -84,15 +84,15 @@ public class AccountEventService(
};
}
public async Task<Dictionary<Guid, Status>> GetStatuses(List<Guid> userIds)
public async Task<Dictionary<Guid, SnAccountStatus>> GetStatuses(List<Guid> userIds)
{
var results = new Dictionary<Guid, Status>();
var results = new Dictionary<Guid, SnAccountStatus>();
var cacheMissUserIds = new List<Guid>();
foreach (var userId in userIds)
{
var cacheKey = $"{StatusCacheKey}{userId}";
var cachedStatus = await cache.GetAsync<Status>(cacheKey);
var cachedStatus = await cache.GetAsync<SnAccountStatus>(cacheKey);
if (cachedStatus != null)
{
cachedStatus.IsOnline = !cachedStatus.IsInvisible && await GetAccountIsConnected(userId);
@@ -132,9 +132,9 @@ public class AccountEventService(
foreach (var userId in usersWithoutStatus)
{
var isOnline = await GetAccountIsConnected(userId);
var defaultStatus = new Status
var defaultStatus = new SnAccountStatus
{
Attitude = StatusAttitude.Neutral,
Attitude = Shared.Models.StatusAttitude.Neutral,
IsOnline = isOnline,
IsCustomized = false,
Label = isOnline ? "Online" : "Offline",
@@ -148,7 +148,7 @@ public class AccountEventService(
return results;
}
public async Task<Status> CreateStatus(Account user, Status status)
public async Task<SnAccountStatus> CreateStatus(SnAccount user, SnAccountStatus status)
{
var now = SystemClock.Instance.GetCurrentInstant();
await db.AccountStatuses
@@ -161,7 +161,7 @@ public class AccountEventService(
return status;
}
public async Task ClearStatus(Account user, Status status)
public async Task ClearStatus(SnAccount user, SnAccountStatus status)
{
status.ClearedAt = SystemClock.Instance.GetCurrentInstant();
db.Update(status);
@@ -173,7 +173,7 @@ public class AccountEventService(
private const string CaptchaCacheKey = "checkin:captcha:";
private const int CaptchaProbabilityPercent = 20;
public async Task<bool> CheckInDailyDoAskCaptcha(Account user)
public async Task<bool> CheckInDailyDoAskCaptcha(SnAccount user)
{
var perkSubscription = await subscriptions.GetPerkSubscriptionAsync(user.Id);
if (perkSubscription is not null) return false;
@@ -188,7 +188,7 @@ public class AccountEventService(
return result;
}
public async Task<bool> CheckInDailyIsAvailable(Account user)
public async Task<bool> CheckInDailyIsAvailable(SnAccount user)
{
var now = SystemClock.Instance.GetCurrentInstant();
var lastCheckIn = await db.AccountCheckInResults
@@ -205,7 +205,7 @@ public class AccountEventService(
return lastDate < currentDate;
}
public async Task<bool> CheckInBackdatedIsAvailable(Account user, Instant backdated)
public async Task<bool> CheckInBackdatedIsAvailable(SnAccount user, Instant backdated)
{
var aDay = Duration.FromDays(1);
var backdatedStart = backdated.ToDateTimeUtc().Date.ToInstant();
@@ -253,7 +253,7 @@ public class AccountEventService(
public const string CheckInLockKey = "checkin:lock:";
public async Task<CheckInResult> CheckInDaily(Account user, Instant? backdated = null)
public async Task<SnCheckInResult> CheckInDaily(SnAccount user, Instant? backdated = null)
{
var lockKey = $"{CheckInLockKey}{user.Id}";
@@ -271,9 +271,7 @@ public class AccountEventService(
// Now try to acquire the lock properly
await using var lockObj =
await cache.AcquireLockAsync(lockKey, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(5));
if (lockObj is null) throw new InvalidOperationException("Check-in was in progress.");
await cache.AcquireLockAsync(lockKey, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(5)) ?? throw new InvalidOperationException("Check-in was in progress.");
var cultureInfo = new CultureInfo(user.Language, false);
CultureInfo.CurrentCulture = cultureInfo;
CultureInfo.CurrentUICulture = cultureInfo;
@@ -283,9 +281,10 @@ public class AccountEventService(
.OrderBy(_ => Random.Next())
.Take(2)
.ToList();
var tips = positiveIndices.Select(index => new FortuneTip
var tips = positiveIndices.Select(index => new CheckInFortuneTip
{
IsPositive = true, Title = localizer[$"FortuneTipPositiveTitle_{index}"].Value,
IsPositive = true,
Title = localizer[$"FortuneTipPositiveTitle_{index}"].Value,
Content = localizer[$"FortuneTipPositiveContent_{index}"].Value
}).ToList();
@@ -295,9 +294,10 @@ public class AccountEventService(
.OrderBy(_ => Random.Next())
.Take(2)
.ToList();
tips.AddRange(negativeIndices.Select(index => new FortuneTip
tips.AddRange(negativeIndices.Select(index => new CheckInFortuneTip
{
IsPositive = false, Title = localizer[$"FortuneTipNegativeTitle_{index}"].Value,
IsPositive = false,
Title = localizer[$"FortuneTipNegativeTitle_{index}"].Value,
Content = localizer[$"FortuneTipNegativeContent_{index}"].Value
}));
@@ -313,7 +313,7 @@ public class AccountEventService(
if (accountBirthday.HasValue && accountBirthday.Value.InUtc().Date == now)
checkInLevel = CheckInResultLevel.Special;
var result = new CheckInResult
var result = new SnCheckInResult
{
Tips = tips,
Level = checkInLevel,
@@ -323,7 +323,7 @@ public class AccountEventService(
BackdatedFrom = backdated.HasValue ? SystemClock.Instance.GetCurrentInstant() : null,
CreatedAt = backdated ?? SystemClock.Instance.GetCurrentInstant(),
};
try
{
if (result.RewardPoints.HasValue)
@@ -354,7 +354,7 @@ public class AccountEventService(
return result;
}
public async Task<List<DailyEventResponse>> GetEventCalendar(Account user, int month, int year = 0,
public async Task<List<DailyEventResponse>> GetEventCalendar(SnAccount user, int month, int year = 0,
bool replaceInvisible = false)
{
if (year == 0)
@@ -368,7 +368,7 @@ public class AccountEventService(
.AsNoTracking()
.TagWith("eventcal:statuses")
.Where(x => x.AccountId == user.Id && x.CreatedAt >= startOfMonth && x.CreatedAt < endOfMonth)
.Select(x => new Status
.Select(x => new SnAccountStatus
{
Id = x.Id,
Attitude = x.Attitude,
@@ -406,7 +406,7 @@ public class AccountEventService(
{
Date = date,
CheckInResult = checkInByDate.GetValueOrDefault(utcDate),
Statuses = statusesByDate.GetValueOrDefault(utcDate, new List<Status>())
Statuses = statusesByDate.GetValueOrDefault(utcDate, new List<SnAccountStatus>())
};
}).ToList();
}

View File

@@ -1,18 +1,14 @@
using System.Globalization;
using System.Text.Json;
using DysonNetwork.Pass.Auth.OpenId;
using DysonNetwork.Pass.Localization;
using DysonNetwork.Pass.Mailer;
using DysonNetwork.Pass.Permission;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Models;
using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Stream;
using EFCore.BulkExtensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using NATS.Client.Core;
using NATS.Client.JetStream;
using NATS.Net;
using NodaTime;
using OtpNet;
@@ -35,7 +31,7 @@ public class AccountService(
INatsConnection nats
)
{
public static void SetCultureInfo(Account account)
public static void SetCultureInfo(SnAccount account)
{
SetCultureInfo(account.Language);
}
@@ -49,12 +45,12 @@ public class AccountService(
public const string AccountCachePrefix = "account:";
public async Task PurgeAccountCache(Account account)
public async Task PurgeAccountCache(SnAccount account)
{
await cache.RemoveGroupAsync($"{AccountCachePrefix}{account.Id}");
}
public async Task<Account?> LookupAccount(string probe)
public async Task<SnAccount?> LookupAccount(string probe)
{
var account = await db.Accounts.Where(a => a.Name == probe).FirstOrDefaultAsync();
if (account is not null) return account;
@@ -66,7 +62,7 @@ public class AccountService(
return contact?.Account;
}
public async Task<Account?> LookupAccountByConnection(string identifier, string provider)
public async Task<SnAccount?> LookupAccountByConnection(string identifier, string provider)
{
var connection = await db.AccountConnections
.Where(c => c.ProvidedIdentifier == identifier && c.Provider == provider)
@@ -83,7 +79,7 @@ public class AccountService(
return profile?.Level;
}
public async Task<Account> CreateAccount(
public async Task<SnAccount> CreateAccount(
string name,
string nick,
string email,
@@ -99,39 +95,39 @@ public class AccountService(
throw new InvalidOperationException("Account name has already been taken.");
var dupeEmailCount = await db.AccountContacts
.Where(c => c.Content == email && c.Type == AccountContactType.Email
.Where(c => c.Content == email && c.Type == Shared.Models.AccountContactType.Email
).CountAsync();
if (dupeEmailCount > 0)
throw new InvalidOperationException("Account email has already been used.");
var account = new Account
var account = new SnAccount
{
Name = name,
Nick = nick,
Language = language,
Region = region,
Contacts = new List<AccountContact>
{
Contacts =
[
new()
{
Type = AccountContactType.Email,
Type = Shared.Models.AccountContactType.Email,
Content = email,
VerifiedAt = isEmailVerified ? SystemClock.Instance.GetCurrentInstant() : null,
IsPrimary = true
}
},
],
AuthFactors = password is not null
? new List<AccountAuthFactor>
? new List<SnAccountAuthFactor>
{
new AccountAuthFactor
new SnAccountAuthFactor
{
Type = AccountAuthFactorType.Password,
Type = Shared.Models.AccountAuthFactorType.Password,
Secret = password,
EnabledAt = SystemClock.Instance.GetCurrentInstant()
}.HashSecret()
}
: [],
Profile = new AccountProfile()
Profile = new SnAccountProfile()
};
if (isActivated)
@@ -166,7 +162,7 @@ public class AccountService(
return account;
}
public async Task<Account> CreateAccount(OidcUserInfo userInfo)
public async Task<SnAccount> CreateAccount(OidcUserInfo userInfo)
{
if (string.IsNullOrEmpty(userInfo.Email))
throw new ArgumentException("Email is required for account creation");
@@ -190,7 +186,7 @@ public class AccountService(
);
}
public async Task<Account> CreateBotAccount(Account account, Guid automatedId, string? pictureId,
public async Task<SnAccount> CreateBotAccount(SnAccount account, Guid automatedId, string? pictureId,
string? backgroundId)
{
var dupeAutomateCount = await db.Accounts.Where(a => a.AutomatedId == automatedId).CountAsync();
@@ -239,12 +235,12 @@ public class AccountService(
return account;
}
public async Task<Account?> GetBotAccount(Guid automatedId)
public async Task<SnAccount?> GetBotAccount(Guid automatedId)
{
return await db.Accounts.FirstOrDefaultAsync(a => a.AutomatedId == automatedId);
}
public async Task RequestAccountDeletion(Account account)
public async Task RequestAccountDeletion(SnAccount account)
{
var spell = await spells.CreateMagicSpell(
account,
@@ -256,7 +252,7 @@ public class AccountService(
await spells.NotifyMagicSpell(spell);
}
public async Task RequestPasswordReset(Account account)
public async Task RequestPasswordReset(SnAccount account)
{
var spell = await spells.CreateMagicSpell(
account,
@@ -268,7 +264,7 @@ public class AccountService(
await spells.NotifyMagicSpell(spell);
}
public async Task<bool> CheckAuthFactorExists(Account account, AccountAuthFactorType type)
public async Task<bool> CheckAuthFactorExists(SnAccount account, Shared.Models.AccountAuthFactorType type)
{
var isExists = await db.AccountAuthFactors
.Where(x => x.AccountId == account.Id && x.Type == type)
@@ -276,45 +272,45 @@ public class AccountService(
return isExists;
}
public async Task<AccountAuthFactor?> CreateAuthFactor(Account account, AccountAuthFactorType type, string? secret)
public async Task<SnAccountAuthFactor?> CreateAuthFactor(SnAccount account, Shared.Models.AccountAuthFactorType type, string? secret)
{
AccountAuthFactor? factor = null;
SnAccountAuthFactor? factor = null;
switch (type)
{
case AccountAuthFactorType.Password:
case Shared.Models.AccountAuthFactorType.Password:
if (string.IsNullOrWhiteSpace(secret)) throw new ArgumentNullException(nameof(secret));
factor = new AccountAuthFactor
factor = new SnAccountAuthFactor
{
Type = AccountAuthFactorType.Password,
Type = Shared.Models.AccountAuthFactorType.Password,
Trustworthy = 1,
AccountId = account.Id,
Secret = secret,
EnabledAt = SystemClock.Instance.GetCurrentInstant(),
}.HashSecret();
break;
case AccountAuthFactorType.EmailCode:
factor = new AccountAuthFactor
case Shared.Models.AccountAuthFactorType.EmailCode:
factor = new SnAccountAuthFactor
{
Type = AccountAuthFactorType.EmailCode,
Type = Shared.Models.AccountAuthFactorType.EmailCode,
Trustworthy = 2,
EnabledAt = SystemClock.Instance.GetCurrentInstant(),
};
break;
case AccountAuthFactorType.InAppCode:
factor = new AccountAuthFactor
case Shared.Models.AccountAuthFactorType.InAppCode:
factor = new SnAccountAuthFactor
{
Type = AccountAuthFactorType.InAppCode,
Type = Shared.Models.AccountAuthFactorType.InAppCode,
Trustworthy = 1,
EnabledAt = SystemClock.Instance.GetCurrentInstant()
};
break;
case AccountAuthFactorType.TimedCode:
case Shared.Models.AccountAuthFactorType.TimedCode:
var skOtp = KeyGeneration.GenerateRandomKey(20);
var skOtp32 = Base32Encoding.ToString(skOtp);
factor = new AccountAuthFactor
factor = new SnAccountAuthFactor
{
Secret = skOtp32,
Type = AccountAuthFactorType.TimedCode,
Type = Shared.Models.AccountAuthFactorType.TimedCode,
Trustworthy = 2,
EnabledAt = null, // It needs to be tired once to enable
CreatedResponse = new Dictionary<string, object>
@@ -328,13 +324,13 @@ public class AccountService(
}
};
break;
case AccountAuthFactorType.PinCode:
case Shared.Models.AccountAuthFactorType.PinCode:
if (string.IsNullOrWhiteSpace(secret)) throw new ArgumentNullException(nameof(secret));
if (!secret.All(char.IsDigit) || secret.Length != 6)
throw new ArgumentException("PIN code must be exactly 6 digits");
factor = new AccountAuthFactor
factor = new SnAccountAuthFactor
{
Type = AccountAuthFactorType.PinCode,
Type = Shared.Models.AccountAuthFactorType.PinCode,
Trustworthy = 0, // Only for confirming, can't be used for login
Secret = secret,
EnabledAt = SystemClock.Instance.GetCurrentInstant(),
@@ -351,10 +347,10 @@ public class AccountService(
return factor;
}
public async Task<AccountAuthFactor> EnableAuthFactor(AccountAuthFactor factor, string? code)
public async Task<SnAccountAuthFactor> EnableAuthFactor(SnAccountAuthFactor factor, string? code)
{
if (factor.EnabledAt is not null) throw new ArgumentException("The factor has been enabled.");
if (factor.Type is AccountAuthFactorType.Password or AccountAuthFactorType.TimedCode)
if (factor.Type is Shared.Models.AccountAuthFactorType.Password or Shared.Models.AccountAuthFactorType.TimedCode)
{
if (code is null || !factor.VerifyPassword(code))
throw new InvalidOperationException(
@@ -369,7 +365,7 @@ public class AccountService(
return factor;
}
public async Task<AccountAuthFactor> DisableAuthFactor(AccountAuthFactor factor)
public async Task<SnAccountAuthFactor> DisableAuthFactor(SnAccountAuthFactor factor)
{
if (factor.EnabledAt is null) throw new ArgumentException("The factor has been disabled.");
@@ -387,7 +383,7 @@ public class AccountService(
return factor;
}
public async Task DeleteAuthFactor(AccountAuthFactor factor)
public async Task DeleteAuthFactor(SnAccountAuthFactor factor)
{
var count = await db.AccountAuthFactors
.Where(f => f.AccountId == factor.AccountId)
@@ -405,13 +401,13 @@ public class AccountService(
/// </summary>
/// <param name="account">The owner of the auth factor</param>
/// <param name="factor">The auth factor needed to send code</param>
public async Task SendFactorCode(Account account, AccountAuthFactor factor)
public async Task SendFactorCode(SnAccount account, SnAccountAuthFactor factor)
{
var code = new Random().Next(100000, 999999).ToString("000000");
switch (factor.Type)
{
case AccountAuthFactorType.InAppCode:
case Shared.Models.AccountAuthFactorType.InAppCode:
if (await _GetFactorCode(factor) is not null)
throw new InvalidOperationException("A factor code has been sent and in active duration.");
@@ -430,12 +426,12 @@ public class AccountService(
);
await _SetFactorCode(factor, code, TimeSpan.FromMinutes(5));
break;
case AccountAuthFactorType.EmailCode:
case Shared.Models.AccountAuthFactorType.EmailCode:
if (await _GetFactorCode(factor) is not null)
throw new InvalidOperationException("A factor code has been sent and in active duration.");
var contact = await db.AccountContacts
.Where(c => c.Type == AccountContactType.Email)
.Where(c => c.Type == Shared.Models.AccountContactType.Email)
.Where(c => c.VerifiedAt != null)
.Where(c => c.IsPrimary)
.Where(c => c.AccountId == account.Id)
@@ -464,27 +460,27 @@ public class AccountService(
await _SetFactorCode(factor, code, TimeSpan.FromMinutes(30));
break;
case AccountAuthFactorType.Password:
case AccountAuthFactorType.TimedCode:
case Shared.Models.AccountAuthFactorType.Password:
case Shared.Models.AccountAuthFactorType.TimedCode:
default:
// No need to send, such as password etc...
return;
}
}
public async Task<bool> VerifyFactorCode(AccountAuthFactor factor, string code)
public async Task<bool> VerifyFactorCode(SnAccountAuthFactor factor, string code)
{
switch (factor.Type)
{
case AccountAuthFactorType.EmailCode:
case AccountAuthFactorType.InAppCode:
case Shared.Models.AccountAuthFactorType.EmailCode:
case Shared.Models.AccountAuthFactorType.InAppCode:
var correctCode = await _GetFactorCode(factor);
var isCorrect = correctCode is not null &&
string.Equals(correctCode, code, StringComparison.OrdinalIgnoreCase);
await cache.RemoveAsync($"{AuthFactorCachePrefix}{factor.Id}:code");
return isCorrect;
case AccountAuthFactorType.Password:
case AccountAuthFactorType.TimedCode:
case Shared.Models.AccountAuthFactorType.Password:
case Shared.Models.AccountAuthFactorType.TimedCode:
default:
return factor.VerifyPassword(code);
}
@@ -492,7 +488,7 @@ public class AccountService(
private const string AuthFactorCachePrefix = "authfactor:";
private async Task _SetFactorCode(AccountAuthFactor factor, string code, TimeSpan expires)
private async Task _SetFactorCode(SnAccountAuthFactor factor, string code, TimeSpan expires)
{
await cache.SetAsync(
$"{AuthFactorCachePrefix}{factor.Id}:code",
@@ -501,7 +497,7 @@ public class AccountService(
);
}
private async Task<string?> _GetFactorCode(AccountAuthFactor factor)
private async Task<string?> _GetFactorCode(SnAccountAuthFactor factor)
{
return await cache.GetAsync<string?>(
$"{AuthFactorCachePrefix}{factor.Id}:code"
@@ -515,7 +511,7 @@ public class AccountService(
.AnyAsync(s => s.Challenge.ClientId == id);
}
public async Task<SnAuthClient> UpdateDeviceName(Account account, string deviceId, string label)
public async Task<SnAuthClient> UpdateDeviceName(SnAccount account, string deviceId, string label)
{
var device = await db.AuthClients.FirstOrDefaultAsync(c => c.DeviceId == deviceId && c.AccountId == account.Id
);
@@ -528,7 +524,7 @@ public class AccountService(
return device;
}
public async Task DeleteSession(Account account, Guid sessionId)
public async Task DeleteSession(SnAccount account, Guid sessionId)
{
var session = await db.AuthSessions
.Include(s => s.Challenge)
@@ -554,7 +550,7 @@ public class AccountService(
await cache.RemoveAsync($"{AuthService.AuthCachePrefix}{session.Id}");
}
public async Task DeleteDevice(Account account, string deviceId)
public async Task DeleteDevice(SnAccount account, string deviceId)
{
var device = await db.AuthClients.FirstOrDefaultAsync(c => c.DeviceId == deviceId && c.AccountId == account.Id
);
@@ -584,7 +580,7 @@ public class AccountService(
await cache.RemoveAsync($"{AuthService.AuthCachePrefix}{item.Id}");
}
public async Task<AccountContact> CreateContactMethod(Account account, AccountContactType type, string content)
public async Task<SnAccountContact> CreateContactMethod(SnAccount account, Shared.Models.AccountContactType type, string content)
{
var isExists = await db.AccountContacts
.Where(x => x.AccountId == account.Id && x.Type == type && x.Content == content)
@@ -592,7 +588,7 @@ public class AccountService(
if (isExists)
throw new InvalidOperationException("Contact method already exists.");
var contact = new AccountContact
var contact = new SnAccountContact
{
Type = type,
Content = content,
@@ -605,7 +601,7 @@ public class AccountService(
return contact;
}
public async Task VerifyContactMethod(Account account, AccountContact contact)
public async Task VerifyContactMethod(SnAccount account, SnAccountContact contact)
{
var spell = await spells.CreateMagicSpell(
account,
@@ -617,7 +613,7 @@ public class AccountService(
await spells.NotifyMagicSpell(spell);
}
public async Task<AccountContact> SetContactMethodPrimary(Account account, AccountContact contact)
public async Task<SnAccountContact> SetContactMethodPrimary(SnAccount account, SnAccountContact contact)
{
if (contact.AccountId != account.Id)
throw new InvalidOperationException("Contact method does not belong to this account.");
@@ -646,7 +642,7 @@ public class AccountService(
}
}
public async Task<AccountContact> SetContactMethodPublic(Account account, AccountContact contact, bool isPublic)
public async Task<SnAccountContact> SetContactMethodPublic(SnAccount account, SnAccountContact contact, bool isPublic)
{
contact.IsPublic = isPublic;
db.AccountContacts.Update(contact);
@@ -654,7 +650,7 @@ public class AccountService(
return contact;
}
public async Task DeleteContactMethod(Account account, AccountContact contact)
public async Task DeleteContactMethod(SnAccount account, SnAccountContact contact)
{
if (contact.AccountId != account.Id)
throw new InvalidOperationException("Contact method does not belong to this account.");
@@ -669,7 +665,7 @@ public class AccountService(
/// This method will grant a badge to the account.
/// Shouldn't be exposed to normal user and the user itself.
/// </summary>
public async Task<AccountBadge> GrantBadge(Account account, AccountBadge badge)
public async Task<SnAccountBadge> GrantBadge(SnAccount account, SnAccountBadge badge)
{
badge.AccountId = account.Id;
db.Badges.Add(badge);
@@ -681,14 +677,12 @@ public class AccountService(
/// This method will revoke a badge from the account.
/// Shouldn't be exposed to normal user and the user itself.
/// </summary>
public async Task RevokeBadge(Account account, Guid badgeId)
public async Task RevokeBadge(SnAccount account, Guid badgeId)
{
var badge = await db.Badges
.Where(b => b.AccountId == account.Id && b.Id == badgeId)
.OrderByDescending(b => b.CreatedAt)
.FirstOrDefaultAsync();
if (badge is null) throw new InvalidOperationException("Badge was not found.");
.FirstOrDefaultAsync() ?? throw new InvalidOperationException("Badge was not found.");
var profile = await db.AccountProfiles
.Where(p => p.AccountId == account.Id)
.FirstOrDefaultAsync();
@@ -699,7 +693,7 @@ public class AccountService(
await db.SaveChangesAsync();
}
public async Task ActiveBadge(Account account, Guid badgeId)
public async Task ActiveBadge(SnAccount account, Guid badgeId)
{
await using var transaction = await db.Database.BeginTransactionAsync();
@@ -733,7 +727,7 @@ public class AccountService(
}
}
public async Task DeleteAccount(Account account)
public async Task DeleteAccount(SnAccount account)
{
await db.AuthSessions
.Where(s => s.AccountId == account.Id)

View File

@@ -236,7 +236,7 @@ public class AccountServiceGrpc(
var relationship = await relationships.GetRelationship(
Guid.Parse(request.AccountId),
Guid.Parse(request.RelatedId),
status: (RelationshipStatus?)request.Status
status: (Shared.Models.RelationshipStatus?)request.Status
);
return new GetRelationshipResponse
{
@@ -256,7 +256,7 @@ public class AccountServiceGrpc(
hasRelationship = await relationships.HasRelationshipWithStatus(
Guid.Parse(request.AccountId),
Guid.Parse(request.RelatedId),
(RelationshipStatus)request.Status
(Shared.Models.RelationshipStatus)request.Status
);
return new BoolValue { Value = hasRelationship };
}

View File

@@ -8,7 +8,7 @@ public class ActionLogService(GeoIpService geo, FlushBufferService fbs)
{
public void CreateActionLog(Guid accountId, string action, Dictionary<string, object?> meta)
{
var log = new ActionLog
var log = new SnActionLog
{
Action = action,
AccountId = accountId,
@@ -19,9 +19,9 @@ public class ActionLogService(GeoIpService geo, FlushBufferService fbs)
}
public void CreateActionLogFromRequest(string action, Dictionary<string, object> meta, HttpRequest request,
Account? account = null)
SnAccount? account = null)
{
var log = new ActionLog
var log = new SnActionLog
{
Action = action,
Meta = meta,
@@ -30,7 +30,7 @@ public class ActionLogService(GeoIpService geo, FlushBufferService fbs)
Location = geo.GetPointFromIp(request.HttpContext.Connection.RemoteIpAddress?.ToString())
};
if (request.HttpContext.Items["CurrentUser"] is Account currentUser)
if (request.HttpContext.Items["CurrentUser"] is SnAccount currentUser)
log.AccountId = currentUser.Id;
else if (account != null)
log.AccountId = account.Id;

View File

@@ -22,7 +22,7 @@ public class BotAccountReceiverGrpc(
ServerCallContext context
)
{
var account = Account.FromProtoValue(request.Account);
var account = SnAccount.FromProtoValue(request.Account);
account = await accounts.CreateBotAccount(
account,
Guid.Parse(request.AutomatedId),
@@ -48,7 +48,7 @@ public class BotAccountReceiverGrpc(
ServerCallContext context
)
{
var account = Account.FromProtoValue(request.Account);
var account = SnAccount.FromProtoValue(request.Account);
if (request.PictureId is not null)
{

View File

@@ -50,7 +50,7 @@ public class MagicSpellController(AppDatabase db, MagicSpellService sp) : Contro
return NotFound();
try
{
if (spell.Type == MagicSpellType.AuthPasswordReset && request?.NewPassword is not null)
if (spell.Type == Shared.Models.MagicSpellType.AuthPasswordReset && request?.NewPassword is not null)
await sp.ApplyPasswordReset(spell, request.NewPassword);
else
await sp.ApplyMagicSpell(spell);

View File

@@ -2,8 +2,8 @@ using System.Security.Cryptography;
using System.Text.Json;
using DysonNetwork.Pass.Emails;
using DysonNetwork.Pass.Mailer;
using DysonNetwork.Pass.Permission;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using NodaTime;
@@ -20,8 +20,8 @@ public class MagicSpellService(
ICacheService cache
)
{
public async Task<MagicSpell> CreateMagicSpell(
Account account,
public async Task<SnMagicSpell> CreateMagicSpell(
SnAccount account,
MagicSpellType type,
Dictionary<string, object> meta,
Instant? expiredAt = null,
@@ -42,7 +42,7 @@ public class MagicSpellService(
}
var spellWord = _GenerateRandomString(128);
var spell = new MagicSpell
var spell = new SnMagicSpell
{
Spell = spellWord,
Type = type,
@@ -60,7 +60,7 @@ public class MagicSpellService(
private const string SpellNotifyCacheKeyPrefix = "spells:notify:";
public async Task NotifyMagicSpell(MagicSpell spell, bool bypassVerify = false)
public async Task NotifyMagicSpell(SnMagicSpell spell, bool bypassVerify = false)
{
var cacheKey = SpellNotifyCacheKeyPrefix + spell.Id;
var (found, _) = await cache.GetAsyncWithStatus<bool?>(cacheKey);
@@ -156,7 +156,7 @@ public class MagicSpellService(
}
}
public async Task ApplyMagicSpell(MagicSpell spell)
public async Task ApplyMagicSpell(SnMagicSpell spell)
{
switch (spell.Type)
{
@@ -191,7 +191,7 @@ public class MagicSpellService(
var defaultGroup = await db.PermissionGroups.FirstOrDefaultAsync(g => g.Key == "default");
if (defaultGroup is not null && account is not null)
{
db.PermissionGroupMembers.Add(new PermissionGroupMember
db.PermissionGroupMembers.Add(new SnPermissionGroupMember
{
Actor = $"user:{account.Id}",
Group = defaultGroup
@@ -218,7 +218,7 @@ public class MagicSpellService(
await db.SaveChangesAsync();
}
public async Task ApplyPasswordReset(MagicSpell spell, string newPassword)
public async Task ApplyPasswordReset(SnMagicSpell spell, string newPassword)
{
if (spell.Type != MagicSpellType.AuthPasswordReset)
throw new ArgumentException("This spell is not a password reset spell.");
@@ -231,7 +231,7 @@ public class MagicSpellService(
{
var account = await db.Accounts.FirstOrDefaultAsync(c => c.Id == spell.AccountId);
if (account is null) throw new InvalidOperationException("Both account and auth factor was not found.");
passwordFactor = new AccountAuthFactor
passwordFactor = new SnAccountAuthFactor
{
Type = AccountAuthFactorType.Password,
Account = account,
@@ -257,6 +257,6 @@ public class MagicSpellService(
var base64String = Convert.ToBase64String(randomBytes);
return base64String.Substring(0, length);
return base64String[..length];
}
}

View File

@@ -1,3 +1,4 @@
using DysonNetwork.Shared.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -26,7 +27,7 @@ public class NotableDaysController(NotableDaysService days) : ControllerBase
[Authorize]
public async Task<ActionResult<List<NotableDay>>> GetAccountNotableDays(int year)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var region = currentUser.Region;
if (string.IsNullOrWhiteSpace(region)) region = "us";
@@ -39,7 +40,7 @@ public class NotableDaysController(NotableDaysService days) : ControllerBase
[Authorize]
public async Task<ActionResult<List<NotableDay>>> GetAccountNotableDaysCurrentYear()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var currentYear = DateTime.Now.Year;
var region = currentUser.Region;
@@ -64,7 +65,7 @@ public class NotableDaysController(NotableDaysService days) : ControllerBase
[Authorize]
public async Task<ActionResult<NotableDay?>> GetAccountNextHoliday()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var region = currentUser.Region;
if (string.IsNullOrWhiteSpace(region)) region = "us";

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@@ -12,10 +13,10 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
{
[HttpGet]
[Authorize]
public async Task<ActionResult<List<Relationship>>> ListRelationships([FromQuery] int offset = 0,
public async Task<ActionResult<List<SnAccountRelationship>>> ListRelationships([FromQuery] int offset = 0,
[FromQuery] int take = 20)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var userId = currentUser.Id;
var query = db.AccountRelationships.AsQueryable()
@@ -44,9 +45,9 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpGet("requests")]
[Authorize]
public async Task<ActionResult<List<Relationship>>> ListSentRequests()
public async Task<ActionResult<List<SnAccountRelationship>>> ListSentRequests()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var relationships = await db.AccountRelationships
.Where(r => r.AccountId == currentUser.Id && r.Status == RelationshipStatus.Pending)
@@ -66,10 +67,10 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpPost("{userId:guid}")]
[Authorize]
public async Task<ActionResult<Relationship>> CreateRelationship(Guid userId,
public async Task<ActionResult<SnAccountRelationship>> CreateRelationship(Guid userId,
[FromBody] RelationshipRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found.");
@@ -89,10 +90,10 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpPatch("{userId:guid}")]
[Authorize]
public async Task<ActionResult<Relationship>> UpdateRelationship(Guid userId,
public async Task<ActionResult<SnAccountRelationship>> UpdateRelationship(Guid userId,
[FromBody] RelationshipRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -111,9 +112,9 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpGet("{userId:guid}")]
[Authorize]
public async Task<ActionResult<Relationship>> GetRelationship(Guid userId)
public async Task<ActionResult<SnAccountRelationship>> GetRelationship(Guid userId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var now = Instant.FromDateTimeUtc(DateTime.UtcNow);
var queries = db.AccountRelationships.AsQueryable()
@@ -131,9 +132,9 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpPost("{userId:guid}/friends")]
[Authorize]
public async Task<ActionResult<Relationship>> SendFriendRequest(Guid userId)
public async Task<ActionResult<SnAccountRelationship>> SendFriendRequest(Guid userId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found.");
@@ -158,7 +159,7 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[Authorize]
public async Task<ActionResult> DeleteFriendRequest(Guid userId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
@@ -173,9 +174,9 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpPost("{userId:guid}/friends/accept")]
[Authorize]
public async Task<ActionResult<Relationship>> AcceptFriendRequest(Guid userId)
public async Task<ActionResult<SnAccountRelationship>> AcceptFriendRequest(Guid userId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var relationship = await rels.GetRelationship(userId, currentUser.Id, RelationshipStatus.Pending);
if (relationship is null) return NotFound("Friend request was not found.");
@@ -193,9 +194,9 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpPost("{userId:guid}/friends/decline")]
[Authorize]
public async Task<ActionResult<Relationship>> DeclineFriendRequest(Guid userId)
public async Task<ActionResult<SnAccountRelationship>> DeclineFriendRequest(Guid userId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var relationship = await rels.GetRelationship(userId, currentUser.Id, RelationshipStatus.Pending);
if (relationship is null) return NotFound("Friend request was not found.");
@@ -213,9 +214,9 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpPost("{userId:guid}/block")]
[Authorize]
public async Task<ActionResult<Relationship>> BlockUser(Guid userId)
public async Task<ActionResult<SnAccountRelationship>> BlockUser(Guid userId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found.");
@@ -233,9 +234,9 @@ public class RelationshipController(AppDatabase db, RelationshipService rels) :
[HttpDelete("{userId:guid}/block")]
[Authorize]
public async Task<ActionResult<Relationship>> UnblockUser(Guid userId)
public async Task<ActionResult<SnAccountRelationship>> UnblockUser(Guid userId)
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
var relatedUser = await db.Accounts.FindAsync(userId);
if (relatedUser is null) return NotFound("Account was not found.");

View File

@@ -1,5 +1,6 @@
using DysonNetwork.Pass.Localization;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Models;
using DysonNetwork.Shared.Proto;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
@@ -26,7 +27,7 @@ public class RelationshipService(
return count > 0;
}
public async Task<Relationship?> GetRelationship(
public async Task<SnAccountRelationship?> GetRelationship(
Guid accountId,
Guid relatedId,
RelationshipStatus? status = null,
@@ -42,7 +43,7 @@ public class RelationshipService(
return relationship;
}
public async Task<Relationship> CreateRelationship(Account sender, Account target, RelationshipStatus status)
public async Task<SnAccountRelationship> CreateRelationship(SnAccount sender, SnAccount target, RelationshipStatus status)
{
if (status == RelationshipStatus.Pending)
throw new InvalidOperationException(
@@ -50,7 +51,7 @@ public class RelationshipService(
if (await HasExistingRelationship(sender.Id, target.Id))
throw new InvalidOperationException("Found existing relationship between you and target user.");
var relationship = new Relationship
var relationship = new SnAccountRelationship
{
AccountId = sender.Id,
RelatedId = target.Id,
@@ -65,14 +66,14 @@ public class RelationshipService(
return relationship;
}
public async Task<Relationship> BlockAccount(Account sender, Account target)
public async Task<SnAccountRelationship> BlockAccount(SnAccount sender, SnAccount target)
{
if (await HasExistingRelationship(sender.Id, target.Id))
return await UpdateRelationship(sender.Id, target.Id, RelationshipStatus.Blocked);
return await CreateRelationship(sender, target, RelationshipStatus.Blocked);
}
public async Task<Relationship> UnblockAccount(Account sender, Account target)
public async Task<SnAccountRelationship> UnblockAccount(SnAccount sender, SnAccount target)
{
var relationship = await GetRelationship(sender.Id, target.Id, RelationshipStatus.Blocked);
if (relationship is null) throw new ArgumentException("There is no relationship between you and the user.");
@@ -84,12 +85,12 @@ public class RelationshipService(
return relationship;
}
public async Task<Relationship> SendFriendRequest(Account sender, Account target)
public async Task<SnAccountRelationship> SendFriendRequest(SnAccount sender, SnAccount target)
{
if (await HasExistingRelationship(sender.Id, target.Id))
throw new InvalidOperationException("Found existing relationship between you and target user.");
var relationship = new Relationship
var relationship = new SnAccountRelationship
{
AccountId = sender.Id,
RelatedId = target.Id,
@@ -128,8 +129,8 @@ public class RelationshipService(
await PurgeRelationshipCache(relationship.AccountId, relationship.RelatedId);
}
public async Task<Relationship> AcceptFriendRelationship(
Relationship relationship,
public async Task<SnAccountRelationship> AcceptFriendRelationship(
SnAccountRelationship relationship,
RelationshipStatus status = RelationshipStatus.Friends
)
{
@@ -144,7 +145,7 @@ public class RelationshipService(
relationship.ExpiredAt = null;
db.Update(relationship);
var relationshipBackward = new Relationship
var relationshipBackward = new SnAccountRelationship
{
AccountId = relationship.RelatedId,
RelatedId = relationship.AccountId,
@@ -159,7 +160,7 @@ public class RelationshipService(
return relationshipBackward;
}
public async Task<Relationship> UpdateRelationship(Guid accountId, Guid relatedId, RelationshipStatus status)
public async Task<SnAccountRelationship> UpdateRelationship(Guid accountId, Guid relatedId, RelationshipStatus status)
{
var relationship = await GetRelationship(accountId, relatedId);
if (relationship is null) throw new ArgumentException("There is no relationship between you and the user.");
@@ -173,7 +174,7 @@ public class RelationshipService(
return relationship;
}
public async Task<List<Guid>> ListAccountFriends(Account account)
public async Task<List<Guid>> ListAccountFriends(SnAccount account)
{
return await ListAccountFriends(account.Id);
}
@@ -197,7 +198,7 @@ public class RelationshipService(
return friends ?? [];
}
public async Task<List<Guid>> ListAccountBlocked(Account account)
public async Task<List<Guid>> ListAccountBlocked(SnAccount account)
{
return await ListAccountBlocked(account.Id);
}