🧱 Localization infrastructure
This commit is contained in:
@@ -1,14 +1,23 @@
|
||||
using DysonNetwork.Sphere.Activity;
|
||||
using DysonNetwork.Sphere.Connection;
|
||||
using DysonNetwork.Sphere.Resources;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using NodaTime;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Account;
|
||||
|
||||
public class AccountEventService(AppDatabase db, ActivityService act, WebSocketService ws, IMemoryCache cache)
|
||||
public class AccountEventService(
|
||||
AppDatabase db,
|
||||
AccountService acc,
|
||||
ActivityService act,
|
||||
WebSocketService ws,
|
||||
IMemoryCache cache
|
||||
)
|
||||
{
|
||||
private static readonly Random Random = new();
|
||||
private const string StatusCacheKey = "account_status_";
|
||||
|
||||
public async Task<Status> GetStatus(long userId)
|
||||
@@ -76,4 +85,84 @@ public class AccountEventService(AppDatabase db, ActivityService act, WebSocketS
|
||||
db.Update(status);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private const int FortuneTipCount = 7; // This will be the max index for each type (positive/negative)
|
||||
private const string CaptchaCacheKey = "checkin_captcha_";
|
||||
private const int CaptchaProbabilityPercent = 20;
|
||||
|
||||
public bool CheckInDailyDoAskCaptcha(Account user)
|
||||
{
|
||||
var cacheKey = $"{CaptchaCacheKey}{user.Id}";
|
||||
if (cache.TryGetValue(cacheKey, out bool? needsCaptcha))
|
||||
return needsCaptcha!.Value;
|
||||
|
||||
var result = Random.Next(100) < CaptchaProbabilityPercent;
|
||||
cache.Set(cacheKey, result, TimeSpan.FromHours(24));
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> CheckInDailyIsAvailable(Account user)
|
||||
{
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var lastCheckIn = await db.AccountCheckInResults
|
||||
.Where(x => x.AccountId == user.Id)
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (lastCheckIn == null)
|
||||
return true;
|
||||
|
||||
var lastDate = lastCheckIn.CreatedAt.InUtc().Date;
|
||||
var currentDate = now.InUtc().Date;
|
||||
|
||||
return lastDate < currentDate;
|
||||
}
|
||||
|
||||
public async Task<CheckInResult> CheckInDaily(Account user)
|
||||
{
|
||||
if (await CheckInDailyIsAvailable(user)) throw new InvalidOperationException("Check-in is not available");
|
||||
|
||||
var localizer = acc.GetEventLocalizer(user.Language);
|
||||
|
||||
// Generate 2 positive tips
|
||||
var positiveIndices = Enumerable.Range(1, FortuneTipCount)
|
||||
.OrderBy(_ => Random.Next())
|
||||
.Take(2)
|
||||
.ToList();
|
||||
var tips = positiveIndices.Select(index => new FortuneTip
|
||||
{
|
||||
IsPositive = true, Title = localizer[$"FortuneTipPositiveTitle_{index}"].Value,
|
||||
Content = localizer[$"FortuneTipPositiveContent_{index}"].Value
|
||||
}).ToList();
|
||||
|
||||
// Generate 2 negative tips
|
||||
var negativeIndices = Enumerable.Range(1, FortuneTipCount)
|
||||
.OrderBy(_ => Random.Next())
|
||||
.Take(2)
|
||||
.ToList();
|
||||
tips.AddRange(negativeIndices.Select(index => new FortuneTip
|
||||
{
|
||||
IsPositive = false, Title = localizer[$"FortuneTipNegativeTitle_{index}"].Value,
|
||||
Content = localizer[$"FortuneTipNegativeContent_{index}"].Value
|
||||
}));
|
||||
|
||||
var result = new CheckInResult
|
||||
{
|
||||
Tips = tips,
|
||||
Level = (CheckInResultLevel)Random.Next(Enum.GetValues<CheckInResultLevel>().Length),
|
||||
AccountId = user.Id
|
||||
};
|
||||
|
||||
db.AccountCheckInResults.Add(result);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
await act.CreateActivity(
|
||||
user,
|
||||
"accounts.check-in",
|
||||
$"account.check-in/{result.Id}",
|
||||
ActivityVisibility.Friends
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user