diff --git a/DysonNetwork.Sphere/Account/AccountController.cs b/DysonNetwork.Sphere/Account/AccountController.cs index 6fa0e67..4f7ba2b 100644 --- a/DysonNetwork.Sphere/Account/AccountController.cs +++ b/DysonNetwork.Sphere/Account/AccountController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NodaTime; +using NodaTime.Extensions; namespace DysonNetwork.Sphere.Account; @@ -261,6 +262,46 @@ public class AccountController( return NoContent(); } + [HttpGet("me/check-in")] + [Authorize] + public async Task> GetCheckInResult() + { + if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); + var userId = currentUser.Id; + + var today = SystemClock.Instance.GetCurrentInstant().InUtc().Date; + var localTime = new TimeOnly(0, 0); + var startOfDay = today.ToDateOnly().ToDateTime(localTime).ToInstant(); + var endOfDay = today.PlusDays(1).ToDateOnly().ToDateTime(localTime).ToInstant(); + + var result = await db.AccountCheckInResults + .Where(x => x.AccountId == userId) + .Where(x => x.CreatedAt >= startOfDay && x.CreatedAt < endOfDay) + .OrderByDescending(x => x.CreatedAt) + .FirstOrDefaultAsync(); + + return result is null ? NotFound() : Ok(result); + } + + [HttpPost("me/check-in")] + [Authorize] + public async Task> DoCheckIn([FromBody] string? captchaToken) + { + if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); + + var isAvailable = await events.CheckInDailyIsAvailable(currentUser); + if (!isAvailable) + return BadRequest("Check-in is not available for today."); + + var needsCaptcha = events.CheckInDailyDoAskCaptcha(currentUser); + if (needsCaptcha && string.IsNullOrWhiteSpace(captchaToken)) + return StatusCode(423, "Captcha is required for this check-in."); + if (!await auth.ValidateCaptcha(captchaToken!)) + return BadRequest("Invalid captcha token."); + + return await events.CheckInDaily(currentUser); + } + [HttpGet("search")] public async Task> Search([FromQuery] string query, [FromQuery] int take = 20) { diff --git a/DysonNetwork.Sphere/Account/AccountEventService.cs b/DysonNetwork.Sphere/Account/AccountEventService.cs index 556c674..0e4a612 100644 --- a/DysonNetwork.Sphere/Account/AccountEventService.cs +++ b/DysonNetwork.Sphere/Account/AccountEventService.cs @@ -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 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 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 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().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; + } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Account/AccountService.cs b/DysonNetwork.Sphere/Account/AccountService.cs index 0ba54b6..71fd234 100644 --- a/DysonNetwork.Sphere/Account/AccountService.cs +++ b/DysonNetwork.Sphere/Account/AccountService.cs @@ -1,10 +1,13 @@ +using System.Globalization; +using DysonNetwork.Sphere.Localization; using DysonNetwork.Sphere.Permission; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Localization; namespace DysonNetwork.Sphere.Account; -public class AccountService(AppDatabase db, PermissionService pm, IMemoryCache cache) +public class AccountService(AppDatabase db, PermissionService pm, IMemoryCache cache, IStringLocalizerFactory localizerFactory) { public async Task PurgeAccountCache(Account account) { @@ -31,4 +34,9 @@ public class AccountService(AppDatabase db, PermissionService pm, IMemoryCache c return null; } + + public IStringLocalizer GetEventLocalizer(string language) + { + return localizerFactory.Create(language, nameof(AccountEventResource)); + } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Account/Status.cs b/DysonNetwork.Sphere/Account/Event.cs similarity index 53% rename from DysonNetwork.Sphere/Account/Status.cs rename to DysonNetwork.Sphere/Account/Event.cs index b408a2c..24b077b 100644 --- a/DysonNetwork.Sphere/Account/Status.cs +++ b/DysonNetwork.Sphere/Account/Event.cs @@ -23,4 +23,30 @@ public class Status : ModelBase public long AccountId { get; set; } public Account Account { get; set; } = null!; +} + +public enum CheckInResultLevel +{ + Worst, + Worse, + Normal, + Better, + Best +} + +public class CheckInResult : ModelBase +{ + public Guid Id { get; set; } = Guid.NewGuid(); + public CheckInResultLevel Level { get; set; } + [Column(TypeName = "jsonb")] public ICollection Tips { get; set; } = new List(); + + public long AccountId { get; set; } + public Account Account { get; set; } = null!; +} + +public class FortuneTip +{ + public bool IsPositive { get; set; } + public string Title { get; set; } = null!; + public string Content { get; set; } = null!; } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Activity/ActivityService.cs b/DysonNetwork.Sphere/Activity/ActivityService.cs index 47e337a..2e0893b 100644 --- a/DysonNetwork.Sphere/Activity/ActivityService.cs +++ b/DysonNetwork.Sphere/Activity/ActivityService.cs @@ -16,7 +16,6 @@ public class ActivityService(AppDatabase db) .Select(e => long.Parse(e.ResourceIdentifier.Split("/").Last())) .Distinct() .ToList(); - if (postsId.Count > 0) { var posts = await db.Posts.Where(e => postsId.Contains(e.Id)) @@ -32,18 +31,68 @@ public class ActivityService(AppDatabase db) var postsDict = posts.ToDictionary(p => p.Id); - for (var idx = 0; idx < input.Count; idx++) + foreach (var item in input) { - var resourceIdentifier = input[idx].ResourceIdentifier; + var resourceIdentifier = item.ResourceIdentifier; if (!resourceIdentifier.StartsWith("posts/")) continue; var postId = long.Parse(resourceIdentifier.Split("/").Last()); - if (postsDict.TryGetValue(postId, out var post) && input[idx].Data is null) + if (postsDict.TryGetValue(postId, out var post) && item.Data is null) { - input[idx].Data = post; + item.Data = post; } } } + var statusesId = input + .Where(e => e.ResourceIdentifier.StartsWith("account.statuses/")) + .Select(e => Guid.Parse(e.ResourceIdentifier.Split("/").Last())) + .Distinct() + .ToList(); + if (statusesId.Count > 0) + { + var statuses = await db.AccountStatuses.Where(e => statusesId.Contains(e.Id)) + .Include(e => e.Account) + .Include(e => e.Account.Profile) + .ToListAsync(); + var statusesDict = statuses.ToDictionary(p => p.Id); + + foreach (var item in input) + { + var resourceIdentifier = item.ResourceIdentifier; + if (!resourceIdentifier.StartsWith("account.statuses/")) continue; + var statusId = Guid.Parse(resourceIdentifier.Split("/").Last()); + if (statusesDict.TryGetValue(statusId, out var status) && item.Data is null) + { + item.Data = status; + } + } + } + + var checkInId = input + .Where(e => e.ResourceIdentifier.StartsWith("account.check-in/")) + .Select(e => Guid.Parse(e.ResourceIdentifier.Split("/").Last())) + .Distinct() + .ToList(); + if (checkInId.Count > 0) + { + var checkIns = await db.AccountCheckInResults.Where(e => checkInId.Contains(e.Id)) + .Include(e => e.Account) + .Include(e => e.Account.Profile) + .ToListAsync(); + var checkInsDict = checkIns.ToDictionary(p => p.Id); + + foreach (var item in input) + { + var resourceIdentifier = item.ResourceIdentifier; + if (!resourceIdentifier.StartsWith("account.check-in/")) continue; + var checkInResultId = Guid.Parse(resourceIdentifier.Split("/").Last()); + if (checkInsDict.TryGetValue(checkInResultId, out var checkIn) && item.Data is null) + { + item.Data = checkIn; + } + } + } + return input; } diff --git a/DysonNetwork.Sphere/AppDatabase.cs b/DysonNetwork.Sphere/AppDatabase.cs index fdd0715..adf2bb6 100644 --- a/DysonNetwork.Sphere/AppDatabase.cs +++ b/DysonNetwork.Sphere/AppDatabase.cs @@ -31,6 +31,7 @@ public class AppDatabase( public DbSet AccountAuthFactors { get; set; } public DbSet AccountRelationships { get; set; } public DbSet AccountStatuses { get; set; } + public DbSet AccountCheckInResults { get; set; } public DbSet Notifications { get; set; } public DbSet NotificationPushSubscriptions { get; set; } diff --git a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj index e34e855..c8b6ba9 100644 --- a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj +++ b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj @@ -59,4 +59,46 @@ + + + ResXFileCodeGenerator + SharedResource.Designer.cs + + + ResXFileCodeGenerator + SharedResource-zh-CN.Designer.cs + + + ResXFileCodeGenerator + AccountEventResource.Designer.cs + + + ResXFileCodeGenerator + AccountEventResource.zh-CN.Designer.cs + + + + + + True + True + SharedResource.resx + + + True + True + SharedResource.zh-CN.resx + + + True + True + AccountEventResource.resx + + + True + True + AccountEventResource.zh-CN.resx + + + diff --git a/DysonNetwork.Sphere/Localization/AccountEventResource.cs b/DysonNetwork.Sphere/Localization/AccountEventResource.cs new file mode 100644 index 0000000..f9abe1f --- /dev/null +++ b/DysonNetwork.Sphere/Localization/AccountEventResource.cs @@ -0,0 +1,6 @@ +namespace DysonNetwork.Sphere.Localization; + +public class AccountEventResource +{ + +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Localization/SharedResource.cs b/DysonNetwork.Sphere/Localization/SharedResource.cs new file mode 100644 index 0000000..06489cc --- /dev/null +++ b/DysonNetwork.Sphere/Localization/SharedResource.cs @@ -0,0 +1,6 @@ +namespace DysonNetwork.Sphere.Localization; + +public class SharedResource +{ + +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Program.cs b/DysonNetwork.Sphere/Program.cs index 171b327..0085e3f 100644 --- a/DysonNetwork.Sphere/Program.cs +++ b/DysonNetwork.Sphere/Program.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Net; using System.Security.Cryptography; using System.Text; @@ -10,11 +11,13 @@ using DysonNetwork.Sphere.Auth; using DysonNetwork.Sphere.Chat; using DysonNetwork.Sphere.Connection; using DysonNetwork.Sphere.Connection.Handlers; +using DysonNetwork.Sphere.Localization; using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Post; using DysonNetwork.Sphere.Realm; using DysonNetwork.Sphere.Storage; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Microsoft.EntityFrameworkCore; @@ -25,7 +28,6 @@ using NodaTime; using NodaTime.Serialization.SystemTextJson; using Quartz; using tusdotnet; -using tusdotnet.Interfaces; using tusdotnet.Models; using tusdotnet.Models.Configuration; using tusdotnet.Stores; @@ -38,6 +40,8 @@ builder.WebHost.ConfigureKestrel(options => options.Limits.MaxRequestBodySize = // Add services to the container. +builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); + builder.Services.AddDbContext(); builder.Services.AddHttpClient(); @@ -47,9 +51,24 @@ builder.Services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower; options.JsonSerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); +}).AddDataAnnotationsLocalization(options => { + options.DataAnnotationLocalizerProvider = (type, factory) => + factory.Create(typeof(SharedResource)); }); builder.Services.AddRazorPages(); +builder.Services.Configure(options => { + var supportedCultures = new[] + { + new CultureInfo("en-US"), + new CultureInfo("zh-CN"), + }; + + options.DefaultRequestCulture = new RequestCulture("en-US"); + options.SupportedCultures = supportedCultures; + options.SupportedUICultures = supportedCultures; +}); + // Other pipelines builder.Services.AddRateLimiter(o => o.AddFixedWindowLimiter(policyName: "fixed", opts => @@ -179,6 +198,8 @@ app.MapOpenApi(); app.UseSwagger(); app.UseSwaggerUI(); +app.UseRequestLocalization(); + app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All diff --git a/DysonNetwork.Sphere/Resources/AccountEventResource.Designer.cs b/DysonNetwork.Sphere/Resources/AccountEventResource.Designer.cs new file mode 100644 index 0000000..4ac1ed6 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/AccountEventResource.Designer.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DysonNetwork.Sphere.Resources { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class AccountEventResource { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal AccountEventResource() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.AccountEventResource", typeof(AccountEventResource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/DysonNetwork.Sphere/Resources/AccountEventResource.resx b/DysonNetwork.Sphere/Resources/AccountEventResource.resx new file mode 100644 index 0000000..a4c5284 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/AccountEventResource.resx @@ -0,0 +1,21 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/AccountEventResource.zh-CN.Designer.cs b/DysonNetwork.Sphere/Resources/AccountEventResource.zh-CN.Designer.cs new file mode 100644 index 0000000..6a22234 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/AccountEventResource.zh-CN.Designer.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DysonNetwork.Sphere.Resources { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class AccountEventResource_zh_CN { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal AccountEventResource_zh_CN() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.AccountEventResource_zh_CN", typeof(AccountEventResource_zh_CN).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static string FortuneTipPositiveTitle_1 { + get { + return ResourceManager.GetString("FortuneTipPositiveTitle_1", resourceCulture); + } + } + + internal static string FortuneTipPositiveContent_1 { + get { + return ResourceManager.GetString("FortuneTipPositiveContent_1", resourceCulture); + } + } + + internal static string FortuneTipNegativeTitle_1_ { + get { + return ResourceManager.GetString("FortuneTipNegativeTitle_1 ", resourceCulture); + } + } + + internal static string FortuneTipPositiveTitle_2 { + get { + return ResourceManager.GetString("FortuneTipPositiveTitle_2", resourceCulture); + } + } + + internal static string FortuneTipPositiveContent_2 { + get { + return ResourceManager.GetString("FortuneTipPositiveContent_2", resourceCulture); + } + } + + internal static string FortuneTipNegativeTitle_2 { + get { + return ResourceManager.GetString("FortuneTipNegativeTitle_2", resourceCulture); + } + } + + internal static string FortuneTipNegativeContent_2 { + get { + return ResourceManager.GetString("FortuneTipNegativeContent_2", resourceCulture); + } + } + + internal static string FortuneTipPositiveTitle_3 { + get { + return ResourceManager.GetString("FortuneTipPositiveTitle_3", resourceCulture); + } + } + + internal static string FortuneTipPositiveContent_3 { + get { + return ResourceManager.GetString("FortuneTipPositiveContent_3", resourceCulture); + } + } + + internal static string FortuneTipNegativeTitle_3 { + get { + return ResourceManager.GetString("FortuneTipNegativeTitle_3", resourceCulture); + } + } + + internal static string FortuneTipNegativeContent_3 { + get { + return ResourceManager.GetString("FortuneTipNegativeContent_3", resourceCulture); + } + } + + internal static string FortuneTipPositiveTitle_4 { + get { + return ResourceManager.GetString("FortuneTipPositiveTitle_4", resourceCulture); + } + } + + internal static string FortuneTipPositiveContent_4 { + get { + return ResourceManager.GetString("FortuneTipPositiveContent_4", resourceCulture); + } + } + + internal static string FortuneTipNegativeTitle_4 { + get { + return ResourceManager.GetString("FortuneTipNegativeTitle_4", resourceCulture); + } + } + + internal static string FortuneTipPositiveTitle_5 { + get { + return ResourceManager.GetString("FortuneTipPositiveTitle_5", resourceCulture); + } + } + + internal static string FortuneTipPositiveContent_5 { + get { + return ResourceManager.GetString("FortuneTipPositiveContent_5", resourceCulture); + } + } + + internal static string FortuneTipNegativeTitle_5 { + get { + return ResourceManager.GetString("FortuneTipNegativeTitle_5", resourceCulture); + } + } + + internal static string FortuneTipNegativeContent_5 { + get { + return ResourceManager.GetString("FortuneTipNegativeContent_5", resourceCulture); + } + } + + internal static string FortuneTipPositiveTitle_6 { + get { + return ResourceManager.GetString("FortuneTipPositiveTitle_6", resourceCulture); + } + } + + internal static string FortuneTipPositiveContent_6 { + get { + return ResourceManager.GetString("FortuneTipPositiveContent_6", resourceCulture); + } + } + + internal static string FortuneTipNegativeTitle_6 { + get { + return ResourceManager.GetString("FortuneTipNegativeTitle_6", resourceCulture); + } + } + + internal static string FortuneTipNegativeContent_6 { + get { + return ResourceManager.GetString("FortuneTipNegativeContent_6", resourceCulture); + } + } + + internal static string FortuneTipPositiveTitle_7 { + get { + return ResourceManager.GetString("FortuneTipPositiveTitle_7", resourceCulture); + } + } + + internal static string FortuneTipPositiveContent_7 { + get { + return ResourceManager.GetString("FortuneTipPositiveContent_7", resourceCulture); + } + } + + internal static string FortuneTipNegativeTitle_7 { + get { + return ResourceManager.GetString("FortuneTipNegativeTitle_7", resourceCulture); + } + } + + internal static string FortuneTipNegativeContent_7 { + get { + return ResourceManager.GetString("FortuneTipNegativeContent_7", resourceCulture); + } + } + } +} diff --git a/DysonNetwork.Sphere/Resources/AccountEventResource.zh-CN.resx b/DysonNetwork.Sphere/Resources/AccountEventResource.zh-CN.resx new file mode 100644 index 0000000..22e53c5 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/AccountEventResource.zh-CN.resx @@ -0,0 +1,99 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 抽卡 + + + 次次出金 + + + 抽卡 + + + 游戏 + + + 升段如破竹 + + + 游戏 + + + 掉分如山崩 + + + 抽奖 + + + 欧气加身 + + + 抽奖 + + + 十连皆寂 + + + 演讲 + + + 妙语连珠 + + + 演讲 + + + 绘图 + + + 灵感如泉涌 + + + 绘图 + + + 下笔如千斤 + + + 编程 + + + 0 error(s), 0 warning(s) + + + 编程 + + + 114 error(s), 514 warning(s) + + + 购物 + + + 汇率低谷 + + + 开箱 + + + 225% 关税 + + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/SharedResource.Designer.cs b/DysonNetwork.Sphere/Resources/SharedResource.Designer.cs new file mode 100644 index 0000000..80f343a --- /dev/null +++ b/DysonNetwork.Sphere/Resources/SharedResource.Designer.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DysonNetwork.Sphere.Resources { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class SharedResource { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SharedResource() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.SharedResource", typeof(SharedResource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/DysonNetwork.Sphere/Resources/SharedResource.resx b/DysonNetwork.Sphere/Resources/SharedResource.resx new file mode 100644 index 0000000..a4c5284 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/SharedResource.resx @@ -0,0 +1,21 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/SharedResource.zh-CN.Designer.cs b/DysonNetwork.Sphere/Resources/SharedResource.zh-CN.Designer.cs new file mode 100644 index 0000000..08101e5 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/SharedResource.zh-CN.Designer.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DysonNetwork.Sphere.Resources { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class SharedResource_zh_CN { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SharedResource_zh_CN() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.SharedResource_zh_CN", typeof(SharedResource_zh_CN).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/DysonNetwork.Sphere/Resources/SharedResource.zh-CN.resx b/DysonNetwork.Sphere/Resources/SharedResource.zh-CN.resx new file mode 100644 index 0000000..a4c5284 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/SharedResource.zh-CN.resx @@ -0,0 +1,21 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index 81083d2..41d3c91 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -32,6 +32,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -60,4 +61,10 @@ ForceIncluded ForceIncluded ForceIncluded - ForceIncluded \ No newline at end of file + ForceIncluded + True + True + False + False + True + False \ No newline at end of file