Use affiliation spell for registeration

This commit is contained in:
2025-12-02 00:54:57 +08:00
parent 13b2e46ecc
commit 2cce5ebf80
5 changed files with 72 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using DysonNetwork.Pass.Affiliation;
using DysonNetwork.Pass.Auth;
using DysonNetwork.Pass.Credit;
using DysonNetwork.Pass.Permission;
@@ -22,6 +23,7 @@ public class AccountController(
SubscriptionService subscriptions,
AccountEventService events,
SocialCreditService socialCreditService,
AffiliationSpellService ars,
GeoIpService geo
) : ControllerBase
{
@@ -103,6 +105,8 @@ public class AccountController(
[MaxLength(32)] public string Language { get; set; } = "en-us";
[Required] public string CaptchaToken { get; set; } = string.Empty;
public string? AffiliationSpell { get; set; }
}
public class AccountCreateValidateRequest
@@ -118,6 +122,8 @@ public class AccountController(
[RegularExpression(@"^[^+]+@[^@]+\.[^@]+$", ErrorMessage = "Email address cannot contain '+' symbol.")]
[MaxLength(1024)]
public string? Email { get; set; }
public string? AffiliationSpell { get; set; }
}
[HttpPost("validate")]
@@ -138,6 +144,12 @@ public class AccountController(
return BadRequest("Email has already been used.");
}
if (request.AffiliationSpell is not null)
{
if (!await ars.CheckAffiliationSpellHasTaken(request.AffiliationSpell))
return BadRequest("No affiliation spell has been found.");
}
return Ok("Everything seems good.");
}

View File

@@ -1,4 +1,5 @@
using System.Globalization;
using DysonNetwork.Pass.Affiliation;
using DysonNetwork.Pass.Auth.OpenId;
using DysonNetwork.Pass.Localization;
using DysonNetwork.Pass.Mailer;
@@ -24,6 +25,7 @@ public class AccountService(
FileService.FileServiceClient files,
FileReferenceService.FileReferenceServiceClient fileRefs,
AccountUsernameService uname,
AffiliationSpellService ars,
EmailService mailer,
RingService.RingServiceClient pusher,
IStringLocalizer<NotificationResource> localizer,
@@ -101,6 +103,7 @@ public class AccountService(
string? password,
string language = "en-US",
string region = "en",
string? affiliationSpell = null,
bool isEmailVerified = false,
bool isActivated = false
)
@@ -122,7 +125,7 @@ public class AccountService(
Region = region,
Contacts =
[
new()
new SnAccountContact
{
Type = Shared.Models.AccountContactType.Email,
Content = email,
@@ -144,6 +147,9 @@ public class AccountService(
Profile = new SnAccountProfile()
};
if (affiliationSpell is not null)
await ars.CreateAffiliationResult(affiliationSpell, $"account:{account.Id}");
if (isActivated)
{
account.ActivatedAt = SystemClock.Instance.GetCurrentInstant();
@@ -193,10 +199,7 @@ public class AccountService(
displayName,
userInfo.Email,
null,
"en-US",
"en",
userInfo.EmailVerified,
userInfo.EmailVerified
isEmailVerified: userInfo.EmailVerified
);
}

View File

@@ -1,3 +1,4 @@
using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -7,9 +8,31 @@ namespace DysonNetwork.Pass.Affiliation;
[ApiController]
[Route("/api/affiliations")]
public class AffiliationSpellController(AppDatabase db) : ControllerBase
public class AffiliationSpellController(AppDatabase db, AffiliationSpellService ars) : ControllerBase
{
[HttpGet("me")]
public class CreateAffiliationSpellRequest
{
[MaxLength(1024)] public string? Spell { get; set; }
}
[HttpPost]
[Authorize]
public async Task<ActionResult<SnAffiliationSpell>> CreateSpell([FromBody] CreateAffiliationSpellRequest request)
{
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
var spell = await ars.CreateAffiliationSpell(currentUser.Id, request.Spell);
return Ok(spell);
}
catch (InvalidOperationException e)
{
return BadRequest(e.Message);
}
}
[HttpGet]
[Authorize]
public async Task<ActionResult<List<SnAffiliationSpell>>> ListCreatedSpells(
[FromQuery(Name = "order")] string orderBy = "date",

View File

@@ -9,8 +9,8 @@ public class AffiliationSpellService(AppDatabase db)
public async Task<SnAffiliationSpell> CreateAffiliationSpell(Guid accountId, string? spellWord)
{
spellWord ??= _GenerateRandomString(8);
var hasTaken = await db.AffiliationSpells.AnyAsync(s => s.Spell == spellWord);
if (hasTaken) throw new InvalidOperationException("The spell has been taken.");
if (await CheckAffiliationSpellHasTaken(spellWord))
throw new InvalidOperationException("The spell has been taken.");
var spell = new SnAffiliationSpell
{
@@ -23,10 +23,26 @@ public class AffiliationSpellService(AppDatabase db)
return spell;
}
public async Task<SnAffiliationSpell?> GetAffiliationSpell(string spellWord)
public async Task<SnAffiliationResult> CreateAffiliationResult(string spellWord, string resourceId)
{
var spell = await db.AffiliationSpells.FirstOrDefaultAsync(s => s.Spell == spellWord);
return spell;
var spell =
await db.AffiliationSpells.FirstOrDefaultAsync(a => a.Spell == spellWord);
if (spell is null) throw new InvalidOperationException("The spell was not found.");
var result = new SnAffiliationResult
{
Spell = spell,
ResourceIdentifier = resourceId
};
db.AffiliationResults.Add(result);
await db.SaveChangesAsync();
return result;
}
public async Task<bool> CheckAffiliationSpellHasTaken(string spellWord)
{
return await db.AffiliationSpells.AnyAsync(s => s.Spell == spellWord);
}
private static string _GenerateRandomString(int length)
@@ -40,6 +56,7 @@ public class AffiliationSpellService(AppDatabase db)
rng.GetBytes(bytes);
result[i] = chars[bytes[0] % chars.Length];
}
return new string(result);
}
}

View File

@@ -11,6 +11,7 @@ using NodaTime.Serialization.SystemTextJson;
using System.Text.Json;
using System.Text.Json.Serialization;
using DysonNetwork.Pass.Account.Presences;
using DysonNetwork.Pass.Affiliation;
using DysonNetwork.Pass.Auth.OidcProvider.Options;
using DysonNetwork.Pass.Auth.OidcProvider.Services;
using DysonNetwork.Pass.Credit;
@@ -159,6 +160,7 @@ public static class ServiceCollectionExtensions
services.AddScoped<ExperienceService>();
services.AddScoped<RealmService>();
services.AddScoped<LotteryService>();
services.AddScoped<AffiliationSpellService>();
services.AddScoped<SpotifyPresenceService>();
services.AddScoped<SteamPresenceService>();