✨ Account region
This commit is contained in:
@@ -18,6 +18,7 @@ public class Account : ModelBase
|
|||||||
[MaxLength(256)] public string Name { get; set; } = string.Empty;
|
[MaxLength(256)] public string Name { get; set; } = string.Empty;
|
||||||
[MaxLength(256)] public string Nick { get; set; } = string.Empty;
|
[MaxLength(256)] public string Nick { get; set; } = string.Empty;
|
||||||
[MaxLength(32)] public string Language { get; set; } = string.Empty;
|
[MaxLength(32)] public string Language { get; set; } = string.Empty;
|
||||||
|
[MaxLength(32)] public string Region { get; set; } = string.Empty;
|
||||||
public Instant? ActivatedAt { get; set; }
|
public Instant? ActivatedAt { get; set; }
|
||||||
public bool IsSuperuser { get; set; } = false;
|
public bool IsSuperuser { get; set; } = false;
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ public class Account : ModelBase
|
|||||||
Name = Name,
|
Name = Name,
|
||||||
Nick = Nick,
|
Nick = Nick,
|
||||||
Language = Language,
|
Language = Language,
|
||||||
|
Region = Region,
|
||||||
ActivatedAt = ActivatedAt?.ToTimestamp(),
|
ActivatedAt = ActivatedAt?.ToTimestamp(),
|
||||||
IsSuperuser = IsSuperuser,
|
IsSuperuser = IsSuperuser,
|
||||||
Profile = Profile.ToProtoValue(),
|
Profile = Profile.ToProtoValue(),
|
||||||
@@ -75,6 +77,7 @@ public class Account : ModelBase
|
|||||||
Name = proto.Name,
|
Name = proto.Name,
|
||||||
Nick = proto.Nick,
|
Nick = proto.Nick,
|
||||||
Language = proto.Language,
|
Language = proto.Language,
|
||||||
|
Region = proto.Region,
|
||||||
ActivatedAt = proto.ActivatedAt?.ToInstant(),
|
ActivatedAt = proto.ActivatedAt?.ToInstant(),
|
||||||
IsSuperuser = proto.IsSuperuser,
|
IsSuperuser = proto.IsSuperuser,
|
||||||
PerkSubscription = proto.PerkSubscription is not null
|
PerkSubscription = proto.PerkSubscription is not null
|
||||||
|
@@ -3,6 +3,7 @@ using DysonNetwork.Pass.Auth;
|
|||||||
using DysonNetwork.Pass.Credit;
|
using DysonNetwork.Pass.Credit;
|
||||||
using DysonNetwork.Pass.Wallet;
|
using DysonNetwork.Pass.Wallet;
|
||||||
using DysonNetwork.Shared.Error;
|
using DysonNetwork.Shared.Error;
|
||||||
|
using DysonNetwork.Shared.GeoIp;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
@@ -17,7 +18,8 @@ public class AccountController(
|
|||||||
AccountService accounts,
|
AccountService accounts,
|
||||||
SubscriptionService subscriptions,
|
SubscriptionService subscriptions,
|
||||||
AccountEventService events,
|
AccountEventService events,
|
||||||
SocialCreditService socialCreditService
|
SocialCreditService socialCreditService,
|
||||||
|
GeoIpService geo
|
||||||
) : ControllerBase
|
) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("{name}")]
|
[HttpGet("{name}")]
|
||||||
@@ -32,10 +34,10 @@ public class AccountController(
|
|||||||
.Where(a => a.Name == name)
|
.Where(a => a.Name == name)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (account is null) return NotFound(ApiError.NotFound(name, traceId: HttpContext.TraceIdentifier));
|
if (account is null) return NotFound(ApiError.NotFound(name, traceId: HttpContext.TraceIdentifier));
|
||||||
|
|
||||||
var perk = await subscriptions.GetPerkSubscriptionAsync(account.Id);
|
var perk = await subscriptions.GetPerkSubscriptionAsync(account.Id);
|
||||||
account.PerkSubscription = perk?.ToReference();
|
account.PerkSubscription = perk?.ToReference();
|
||||||
|
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,9 +50,11 @@ public class AccountController(
|
|||||||
.Include(e => e.Badges)
|
.Include(e => e.Badges)
|
||||||
.Where(a => a.Name == name)
|
.Where(a => a.Name == name)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
return account is null ? NotFound(ApiError.NotFound(name, traceId: HttpContext.TraceIdentifier)) : account.Badges.ToList();
|
return account is null
|
||||||
|
? NotFound(ApiError.NotFound(name, traceId: HttpContext.TraceIdentifier))
|
||||||
|
: account.Badges.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{name}/credits")]
|
[HttpGet("{name}/credits")]
|
||||||
[ProducesResponseType<double>(StatusCodes.Status200OK)]
|
[ProducesResponseType<double>(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
@@ -60,12 +64,12 @@ public class AccountController(
|
|||||||
.Where(a => a.Name == name)
|
.Where(a => a.Name == name)
|
||||||
.Select(a => new { a.Id })
|
.Select(a => new { a.Id })
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
if (account is null)
|
if (account is null)
|
||||||
{
|
{
|
||||||
return NotFound(ApiError.NotFound(name, traceId: HttpContext.TraceIdentifier));
|
return NotFound(ApiError.NotFound(name, traceId: HttpContext.TraceIdentifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
var credits = await socialCreditService.GetSocialCredit(account.Id);
|
var credits = await socialCreditService.GetSocialCredit(account.Id);
|
||||||
return credits;
|
return credits;
|
||||||
}
|
}
|
||||||
@@ -93,7 +97,7 @@ public class AccountController(
|
|||||||
[MaxLength(128)]
|
[MaxLength(128)]
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; } = string.Empty;
|
||||||
|
|
||||||
[MaxLength(128)] public string Language { get; set; } = "en-us";
|
[MaxLength(32)] public string Language { get; set; } = "en-us";
|
||||||
|
|
||||||
[Required] public string CaptchaToken { get; set; } = string.Empty;
|
[Required] public string CaptchaToken { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
@@ -109,6 +113,10 @@ public class AccountController(
|
|||||||
[nameof(request.CaptchaToken)] = ["Invalid captcha token."]
|
[nameof(request.CaptchaToken)] = ["Invalid captcha token."]
|
||||||
}, traceId: HttpContext.TraceIdentifier));
|
}, traceId: HttpContext.TraceIdentifier));
|
||||||
|
|
||||||
|
var ip = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||||
|
if (ip is null) return BadRequest(ApiError.NotFound(request.Name, traceId: HttpContext.TraceIdentifier));
|
||||||
|
var region = geo.GetFromIp(ip)?.Country.IsoCode ?? "us";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var account = await accounts.CreateAccount(
|
var account = await accounts.CreateAccount(
|
||||||
@@ -116,7 +124,8 @@ public class AccountController(
|
|||||||
request.Nick,
|
request.Nick,
|
||||||
request.Email,
|
request.Email,
|
||||||
request.Password,
|
request.Password,
|
||||||
request.Language
|
request.Language,
|
||||||
|
region
|
||||||
);
|
);
|
||||||
return Ok(account);
|
return Ok(account);
|
||||||
}
|
}
|
||||||
|
@@ -52,6 +52,7 @@ public class AccountCurrentController(
|
|||||||
{
|
{
|
||||||
[MaxLength(256)] public string? Nick { get; set; }
|
[MaxLength(256)] public string? Nick { get; set; }
|
||||||
[MaxLength(32)] public string? Language { get; set; }
|
[MaxLength(32)] public string? Language { get; set; }
|
||||||
|
[MaxLength(32)] public string? Region { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch]
|
[HttpPatch]
|
||||||
@@ -63,6 +64,7 @@ public class AccountCurrentController(
|
|||||||
|
|
||||||
if (request.Nick is not null) account.Nick = request.Nick;
|
if (request.Nick is not null) account.Nick = request.Nick;
|
||||||
if (request.Language is not null) account.Language = request.Language;
|
if (request.Language is not null) account.Language = request.Language;
|
||||||
|
if (request.Region is not null) account.Region = request.Region;
|
||||||
|
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
await accounts.PurgeAccountCache(currentUser);
|
await accounts.PurgeAccountCache(currentUser);
|
||||||
|
@@ -88,6 +88,7 @@ public class AccountService(
|
|||||||
string email,
|
string email,
|
||||||
string? password,
|
string? password,
|
||||||
string language = "en-US",
|
string language = "en-US",
|
||||||
|
string region = "en",
|
||||||
bool isEmailVerified = false,
|
bool isEmailVerified = false,
|
||||||
bool isActivated = false
|
bool isActivated = false
|
||||||
)
|
)
|
||||||
@@ -107,6 +108,7 @@ public class AccountService(
|
|||||||
Name = name,
|
Name = name,
|
||||||
Nick = nick,
|
Nick = nick,
|
||||||
Language = language,
|
Language = language,
|
||||||
|
Region = region,
|
||||||
Contacts = new List<AccountContact>
|
Contacts = new List<AccountContact>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
@@ -181,6 +183,7 @@ public class AccountService(
|
|||||||
userInfo.Email,
|
userInfo.Email,
|
||||||
null,
|
null,
|
||||||
"en-US",
|
"en-US",
|
||||||
|
"en",
|
||||||
userInfo.EmailVerified,
|
userInfo.EmailVerified,
|
||||||
userInfo.EmailVerified
|
userInfo.EmailVerified
|
||||||
);
|
);
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="Nager.Holiday" Version="1.0.1" />
|
||||||
<PackageReference Include="NATS.Client.Core" Version="2.6.6" />
|
<PackageReference Include="NATS.Client.Core" Version="2.6.6" />
|
||||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.7.115">
|
<PackageReference Include="Nerdbank.GitVersioning" Version="3.7.115">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
2027
DysonNetwork.Pass/Migrations/20250906174610_AddAccountRegion.Designer.cs
generated
Normal file
2027
DysonNetwork.Pass/Migrations/20250906174610_AddAccountRegion.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace DysonNetwork.Pass.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddAccountRegion : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "region",
|
||||||
|
table: "accounts",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "region",
|
||||||
|
table: "accounts");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -132,6 +132,12 @@ namespace DysonNetwork.Pass.Migrations
|
|||||||
.HasColumnType("character varying(256)")
|
.HasColumnType("character varying(256)")
|
||||||
.HasColumnName("nick");
|
.HasColumnName("nick");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasColumnName("region");
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
b.Property<Instant>("UpdatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("updated_at");
|
.HasColumnName("updated_at");
|
||||||
|
@@ -18,6 +18,7 @@ message Account {
|
|||||||
string name = 2;
|
string name = 2;
|
||||||
string nick = 3;
|
string nick = 3;
|
||||||
string language = 4;
|
string language = 4;
|
||||||
|
string region = 18;
|
||||||
google.protobuf.Timestamp activated_at = 5;
|
google.protobuf.Timestamp activated_at = 5;
|
||||||
bool is_superuser = 6;
|
bool is_superuser = 6;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user