♻️ Finish centerlizing the data models
This commit is contained in:
@@ -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 [];
|
||||
|
@@ -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)
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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 };
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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);
|
||||
|
@@ -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];
|
||||
}
|
||||
}
|
@@ -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";
|
||||
|
@@ -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.");
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user