--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Authorization;
7 | using Microsoft.AspNetCore.Identity;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.AspNetCore.Mvc.RazorPages;
10 | using Microsoft.AspNetCore.WebUtilities;
11 | using PcrBattleChannel.Models;
12 |
13 | namespace PcrBattleChannel.Areas.Identity.Pages.Account
14 | {
15 | [AllowAnonymous]
16 | public class ConfirmEmailModel : PageModel
17 | {
18 | private readonly UserManager _userManager;
19 |
20 | public ConfirmEmailModel(UserManager userManager)
21 | {
22 | _userManager = userManager;
23 | }
24 |
25 | [TempData]
26 | public string StatusMessage { get; set; }
27 |
28 | public async Task OnGetAsync(string userId, string code)
29 | {
30 | if (userId == null || code == null)
31 | {
32 | return RedirectToPage("/Index");
33 | }
34 |
35 | var user = await _userManager.FindByIdAsync(userId);
36 | if (user == null)
37 | {
38 | return NotFound($"Unable to load user with ID '{userId}'.");
39 | }
40 |
41 | code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
42 | var result = await _userManager.ConfirmEmailAsync(user, code);
43 | StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email.";
44 | return Page();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ConfirmEmailChangeModel
3 | @{
4 | ViewData["Title"] = "Confirm email change";
5 | }
6 |
7 |
@ViewData["Title"]
8 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Authorization;
7 | using Microsoft.AspNetCore.Identity;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.AspNetCore.Mvc.RazorPages;
10 | using Microsoft.AspNetCore.WebUtilities;
11 | using PcrBattleChannel.Models;
12 |
13 | namespace PcrBattleChannel.Areas.Identity.Pages.Account
14 | {
15 | [AllowAnonymous]
16 | public class ConfirmEmailChangeModel : PageModel
17 | {
18 | private readonly UserManager _userManager;
19 | private readonly SignInManager _signInManager;
20 |
21 | public ConfirmEmailChangeModel(UserManager userManager, SignInManager signInManager)
22 | {
23 | _userManager = userManager;
24 | _signInManager = signInManager;
25 | }
26 |
27 | [TempData]
28 | public string StatusMessage { get; set; }
29 |
30 | public async Task OnGetAsync(string userId, string email, string code)
31 | {
32 | if (userId == null || email == null || code == null)
33 | {
34 | return RedirectToPage("/Index");
35 | }
36 |
37 | var user = await _userManager.FindByIdAsync(userId);
38 | if (user == null)
39 | {
40 | return NotFound($"Unable to load user with ID '{userId}'.");
41 | }
42 |
43 | code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
44 | var result = await _userManager.ChangeEmailAsync(user, email, code);
45 | if (!result.Succeeded)
46 | {
47 | StatusMessage = "Error changing email.";
48 | return Page();
49 | }
50 |
51 | // In our UI email and user name are one and the same, so when we update the email
52 | // we need to update the user name.
53 | var setUserNameResult = await _userManager.SetUserNameAsync(user, email);
54 | if (!setUserNameResult.Succeeded)
55 | {
56 | StatusMessage = "Error changing user name.";
57 | return Page();
58 | }
59 |
60 | await _signInManager.RefreshSignInAsync(user);
61 | StatusMessage = "Thank you for confirming your email change.";
62 | return Page();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/ExternalLogin.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ExternalLoginModel
3 | @{
4 | ViewData["Title"] = "Register";
5 | }
6 |
7 |
@ViewData["Title"]
8 |
Associate your @Model.ProviderDisplayName account.
9 |
10 |
11 |
12 | You've successfully authenticated with @Model.ProviderDisplayName.
13 | Please enter an email address for this site below and click the Register button to finish
14 | logging in.
15 |
10 | You have requested to log in with a recovery code. This login will not be remembered until you provide
11 | an authenticator app code at log in or disable 2FA and log in again.
12 |
16 | Disabling 2FA does not change the keys used in authenticator apps. If you wish to change the key
17 | used in an authenticator app you should reset your authenticator keys.
18 |
19 |
20 |
21 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 | using PcrBattleChannel.Models;
10 |
11 | namespace PcrBattleChannel.Areas.Identity.Pages.Account.Manage
12 | {
13 | public class Disable2faModel : PageModel
14 | {
15 | private readonly UserManager _userManager;
16 | private readonly ILogger _logger;
17 |
18 | public Disable2faModel(
19 | UserManager userManager,
20 | ILogger logger)
21 | {
22 | _userManager = userManager;
23 | _logger = logger;
24 | }
25 |
26 | [TempData]
27 | public string StatusMessage { get; set; }
28 |
29 | public async Task OnGet()
30 | {
31 | var user = await _userManager.GetUserAsync(User);
32 | if (user == null)
33 | {
34 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
35 | }
36 |
37 | if (!await _userManager.GetTwoFactorEnabledAsync(user))
38 | {
39 | throw new InvalidOperationException($"Cannot disable 2FA for user with ID '{_userManager.GetUserId(User)}' as it's not currently enabled.");
40 | }
41 |
42 | return Page();
43 | }
44 |
45 | public async Task OnPostAsync()
46 | {
47 | var user = await _userManager.GetUserAsync(User);
48 | if (user == null)
49 | {
50 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
51 | }
52 |
53 | var disable2faResult = await _userManager.SetTwoFactorEnabledAsync(user, false);
54 | if (!disable2faResult.Succeeded)
55 | {
56 | throw new InvalidOperationException($"Unexpected error occurred disabling 2FA for user with ID '{_userManager.GetUserId(User)}'.");
57 | }
58 |
59 | _logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", _userManager.GetUserId(User));
60 | StatusMessage = "2fa has been disabled. You can reenable 2fa when you setup an authenticator app";
61 | return RedirectToPage("./TwoFactorAuthentication");
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model DownloadPersonalDataModel
3 | @{
4 | ViewData["Title"] = "Download Your Data";
5 | ViewData["ActivePage"] = ManageNavPages.PersonalData;
6 | }
7 |
8 |
@ViewData["Title"]
9 |
10 | @section Scripts {
11 |
12 | }
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.Json;
6 | using System.Threading.Tasks;
7 | using Microsoft.AspNetCore.Identity;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.AspNetCore.Mvc.RazorPages;
10 | using Microsoft.Extensions.Logging;
11 | using PcrBattleChannel.Models;
12 |
13 | namespace PcrBattleChannel.Areas.Identity.Pages.Account.Manage
14 | {
15 | public class DownloadPersonalDataModel : PageModel
16 | {
17 | private readonly UserManager _userManager;
18 | private readonly ILogger _logger;
19 |
20 | public DownloadPersonalDataModel(
21 | UserManager userManager,
22 | ILogger logger)
23 | {
24 | _userManager = userManager;
25 | _logger = logger;
26 | }
27 |
28 | public async Task OnPostAsync()
29 | {
30 | var user = await _userManager.GetUserAsync(User);
31 | if (user == null)
32 | {
33 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
34 | }
35 |
36 | _logger.LogInformation("User with ID '{UserId}' asked for their personal data.", _userManager.GetUserId(User));
37 |
38 | // Only include personal data for download
39 | var personalData = new Dictionary();
40 | var personalDataProps = typeof(PcrIdentityUser).GetProperties().Where(
41 | prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute)));
42 | foreach (var p in personalDataProps)
43 | {
44 | personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null");
45 | }
46 |
47 | var logins = await _userManager.GetLoginsAsync(user);
48 | foreach (var l in logins)
49 | {
50 | personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey);
51 | }
52 |
53 | Response.Headers.Add("Content-Disposition", "attachment; filename=PersonalData.json");
54 | return new FileContentResult(JsonSerializer.SerializeToUtf8Bytes(personalData), "application/json");
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/Manage/Email.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model EmailModel
3 | @{
4 | ViewData["Title"] = "Manage Email";
5 | ViewData["ActivePage"] = ManageNavPages.Email;
6 | }
7 |
8 |
To use an authenticator app go through the following steps:
12 |
13 |
14 |
15 | Download a two-factor authenticator app like Microsoft Authenticator for
16 | Android and
17 | iOS or
18 | Google Authenticator for
19 | Android and
20 | iOS.
21 |
22 |
23 |
24 |
Scan the QR Code or enter this key @Model.SharedKey into your two factor authenticator app. Spaces and casing do not matter.
31 | Once you have scanned the QR code or input the key above, your two factor authentication app will provide you
32 | with a unique code. Enter the code in the confirmation box below.
33 |
16 | If you lose your device and don't have the recovery codes you will lose access to your account.
17 |
18 |
19 | Generating new recovery codes does not change the keys used in authenticator apps. If you wish to change the key
20 | used in an authenticator app you should reset your authenticator keys.
21 |
12 |
13 | If you reset your authenticator key your authenticator app will not work until you reconfigure it.
14 |
15 |
16 | This process disables 2FA until you verify your authenticator app.
17 | If you do not complete your authenticator app configuration you may lose access to your account.
18 |
19 |
20 |
21 |
24 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 | using PcrBattleChannel.Models;
10 |
11 | namespace PcrBattleChannel.Areas.Identity.Pages.Account.Manage
12 | {
13 | public class ResetAuthenticatorModel : PageModel
14 | {
15 | UserManager _userManager;
16 | private readonly SignInManager _signInManager;
17 | ILogger _logger;
18 |
19 | public ResetAuthenticatorModel(
20 | UserManager userManager,
21 | SignInManager signInManager,
22 | ILogger logger)
23 | {
24 | _userManager = userManager;
25 | _signInManager = signInManager;
26 | _logger = logger;
27 | }
28 |
29 | [TempData]
30 | public string StatusMessage { get; set; }
31 |
32 | public async Task OnGet()
33 | {
34 | var user = await _userManager.GetUserAsync(User);
35 | if (user == null)
36 | {
37 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
38 | }
39 |
40 | return Page();
41 | }
42 |
43 | public async Task OnPostAsync()
44 | {
45 | var user = await _userManager.GetUserAsync(User);
46 | if (user == null)
47 | {
48 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
49 | }
50 |
51 | await _userManager.SetTwoFactorEnabledAsync(user, false);
52 | await _userManager.ResetAuthenticatorKeyAsync(user);
53 | _logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", user.Id);
54 |
55 | await _signInManager.RefreshSignInAsync(user);
56 | StatusMessage = "Your authenticator app key has been reset, you will need to configure your authenticator app using the new key.";
57 |
58 | return RedirectToPage("./EnableAuthenticator");
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model SetPasswordModel
3 | @{
4 | ViewData["Title"] = "Set password";
5 | ViewData["ActivePage"] = ManageNavPages.ChangePassword;
6 | }
7 |
8 |
Set your password
9 |
10 |
11 | You do not have a local username/password for this site. Add a local
12 | account so you can log in without an external login.
13 |
12 | This app does not currently have a real email sender registered, see these docs for how to configure a real email sender.
13 | Normally this would be emailed: Click here to confirm your account
14 |
15 | }
16 | else
17 | {
18 |
19 | Please check your email to confirm your account.
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Authorization;
2 | using System.Text;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Identity;
5 | using Microsoft.AspNetCore.Identity.UI.Services;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.AspNetCore.WebUtilities;
9 | using PcrBattleChannel.Models;
10 |
11 | namespace PcrBattleChannel.Areas.Identity.Pages.Account
12 | {
13 | [AllowAnonymous]
14 | public class RegisterConfirmationModel : PageModel
15 | {
16 | private readonly UserManager _userManager;
17 | private readonly IEmailSender _sender;
18 |
19 | public RegisterConfirmationModel(UserManager userManager, IEmailSender sender)
20 | {
21 | _userManager = userManager;
22 | _sender = sender;
23 | }
24 |
25 | public string Email { get; set; }
26 |
27 | public bool DisplayConfirmAccountLink { get; set; }
28 |
29 | public string EmailConfirmationUrl { get; set; }
30 |
31 | public async Task OnGetAsync(string email, string returnUrl = null)
32 | {
33 | if (email == null)
34 | {
35 | return RedirectToPage("/Index");
36 | }
37 |
38 | var user = await _userManager.FindByEmailAsync(email);
39 | if (user == null)
40 | {
41 | return NotFound($"Unable to load user with email '{email}'.");
42 | }
43 |
44 | Email = email;
45 | // Once you add a real email sender, you should remove this code that lets you confirm the account
46 | DisplayConfirmAccountLink = true;
47 | if (DisplayConfirmAccountLink)
48 | {
49 | var userId = await _userManager.GetUserIdAsync(user);
50 | var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
51 | code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
52 | EmailConfirmationUrl = Url.Page(
53 | "/Account/ConfirmEmail",
54 | pageHandler: null,
55 | values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
56 | protocol: Request.Scheme);
57 | }
58 |
59 | return Page();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ResendEmailConfirmationModel
3 | @{
4 | ViewData["Title"] = "Resend email confirmation";
5 | }
6 |
7 |
19 | Swapping to Development environment will display more detailed information about the error that occurred.
20 |
21 |
22 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application.
23 |
24 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/Error.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.AspNetCore.Mvc.RazorPages;
5 |
6 | namespace PcrBattleChannel.Areas.Identity.Pages
7 | {
8 | [AllowAnonymous]
9 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
10 | public class ErrorModel : PageModel
11 | {
12 | public string RequestId { get; set; }
13 |
14 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
15 |
16 | public void OnGet()
17 | {
18 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using Microsoft.AspNetCore.Identity
2 | @using PcrBattleChannel.Areas.Identity
3 | @using PcrBattleChannel.Areas.Identity.Pages
4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
5 |
--------------------------------------------------------------------------------
/Areas/Identity/Pages/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "/Pages/Shared/_Layout.cshtml";
3 | }
4 |
--------------------------------------------------------------------------------
/Migrations/20210127035918_RedundantComboData.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | namespace PcrBattleChannel.Migrations
4 | {
5 | public partial class RedundantComboData : Migration
6 | {
7 | protected override void Up(MigrationBuilder migrationBuilder)
8 | {
9 | migrationBuilder.AddColumn(
10 | name: "Boss1",
11 | table: "UserCombos",
12 | type: "INTEGER",
13 | nullable: false,
14 | defaultValue: 0);
15 |
16 | migrationBuilder.AddColumn(
17 | name: "Boss2",
18 | table: "UserCombos",
19 | type: "INTEGER",
20 | nullable: false,
21 | defaultValue: 0);
22 |
23 | migrationBuilder.AddColumn(
24 | name: "Boss3",
25 | table: "UserCombos",
26 | type: "INTEGER",
27 | nullable: false,
28 | defaultValue: 0);
29 |
30 | migrationBuilder.AddColumn(
31 | name: "Damage1",
32 | table: "UserCombos",
33 | type: "INTEGER",
34 | nullable: false,
35 | defaultValue: 0);
36 |
37 | migrationBuilder.AddColumn(
38 | name: "Damage2",
39 | table: "UserCombos",
40 | type: "INTEGER",
41 | nullable: false,
42 | defaultValue: 0);
43 |
44 | migrationBuilder.AddColumn(
45 | name: "Damage3",
46 | table: "UserCombos",
47 | type: "INTEGER",
48 | nullable: false,
49 | defaultValue: 0);
50 | }
51 |
52 | protected override void Down(MigrationBuilder migrationBuilder)
53 | {
54 | migrationBuilder.DropColumn(
55 | name: "Boss1",
56 | table: "UserCombos");
57 |
58 | migrationBuilder.DropColumn(
59 | name: "Boss2",
60 | table: "UserCombos");
61 |
62 | migrationBuilder.DropColumn(
63 | name: "Boss3",
64 | table: "UserCombos");
65 |
66 | migrationBuilder.DropColumn(
67 | name: "Damage1",
68 | table: "UserCombos");
69 |
70 | migrationBuilder.DropColumn(
71 | name: "Damage2",
72 | table: "UserCombos");
73 |
74 | migrationBuilder.DropColumn(
75 | name: "Damage3",
76 | table: "UserCombos");
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Migrations/20210127221630_UpdateUserForSync.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore.Migrations;
3 |
4 | namespace PcrBattleChannel.Migrations
5 | {
6 | public partial class UpdateUserForSync : Migration
7 | {
8 | protected override void Up(MigrationBuilder migrationBuilder)
9 | {
10 | migrationBuilder.AlterColumn(
11 | name: "LastComboUpdate",
12 | table: "AspNetUsers",
13 | type: "TEXT",
14 | nullable: false,
15 | defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
16 | oldClrType: typeof(DateTime),
17 | oldType: "TEXT",
18 | oldNullable: true);
19 |
20 | migrationBuilder.AddColumn(
21 | name: "DisableYobotSync",
22 | table: "AspNetUsers",
23 | type: "INTEGER",
24 | nullable: false,
25 | defaultValue: false);
26 |
27 | migrationBuilder.AddColumn(
28 | name: "LastConfirm",
29 | table: "AspNetUsers",
30 | type: "TEXT",
31 | nullable: false,
32 | defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
33 | }
34 |
35 | protected override void Down(MigrationBuilder migrationBuilder)
36 | {
37 | migrationBuilder.DropColumn(
38 | name: "DisableYobotSync",
39 | table: "AspNetUsers");
40 |
41 | migrationBuilder.DropColumn(
42 | name: "LastConfirm",
43 | table: "AspNetUsers");
44 |
45 | migrationBuilder.AlterColumn(
46 | name: "LastComboUpdate",
47 | table: "AspNetUsers",
48 | type: "TEXT",
49 | nullable: true,
50 | oldClrType: typeof(DateTime),
51 | oldType: "TEXT");
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Migrations/20210130173603_UpdateUserForComboCalc.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | namespace PcrBattleChannel.Migrations
4 | {
5 | public partial class UpdateUserForComboCalc : Migration
6 | {
7 | protected override void Up(MigrationBuilder migrationBuilder)
8 | {
9 | migrationBuilder.AddColumn(
10 | name: "ComboIncludesDrafts",
11 | table: "AspNetUsers",
12 | type: "INTEGER",
13 | nullable: false,
14 | defaultValue: false);
15 |
16 | migrationBuilder.AddColumn(
17 | name: "IsValueApproximate",
18 | table: "AspNetUsers",
19 | type: "INTEGER",
20 | nullable: false,
21 | defaultValue: false);
22 | }
23 |
24 | protected override void Down(MigrationBuilder migrationBuilder)
25 | {
26 | migrationBuilder.DropColumn(
27 | name: "ComboIncludesDrafts",
28 | table: "AspNetUsers");
29 |
30 | migrationBuilder.DropColumn(
31 | name: "IsValueApproximate",
32 | table: "AspNetUsers");
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Models/BattleStage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | public class BattleStage
10 | {
11 | public int BattleStageID { get; set; }
12 |
13 | [ForeignKey(nameof(GlobalData))]
14 | public int GlobalDataID { get; set; }
15 | public GlobalData GlobalData { get; set; }
16 |
17 | public int Order { get; set; }
18 | public string Name { get; set; }
19 | public string ShortName { get; set; }
20 | public int StartLap { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Models/Boss.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | public class Boss
10 | {
11 | public int BossID { get; set; }
12 |
13 | [ForeignKey(nameof(BattleStage))]
14 | public int BattleStageID { get; set; }
15 | public BattleStage BattleStage { get; set; }
16 |
17 | public string Name { get; set; }
18 | public string ShortName { get; set; }
19 | public int Life { get; set; }
20 | public float Score { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Models/Character.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | public class Character
10 | {
11 | public int CharacterID { get; set; }
12 |
13 | [Display(Name = "游戏ID")]
14 | public int InternalID { get; set; }
15 | [Display(Name = "角色名")]
16 | public string Name { get; set; }
17 | [Display(Name = "初始星级")]
18 | public int Rarity { get; set; }
19 | [Display(Name = "专武")]
20 | public bool HasWeapon { get; set; }
21 | [Display(Name = "攻击距离")]
22 | public float Range { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Models/CharacterAliasProvider.cs:
--------------------------------------------------------------------------------
1 | using CsvHelper;
2 | using CsvHelper.Configuration;
3 | using CsvHelper.Configuration.Attributes;
4 | using PcrBattleChannel.Algorithm;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Globalization;
8 | using System.IO;
9 | using System.Linq;
10 | using System.Reflection;
11 | using System.Threading.Tasks;
12 |
13 | namespace PcrBattleChannel.Models
14 | {
15 | public interface ICharacterAliasProvider
16 | {
17 | bool TryGet(ref ReadOnlySpan input, out string keyResult, out int idResult);
18 | }
19 |
20 | public class CharacterAliasProvider : ICharacterAliasProvider
21 | {
22 | public class Entry
23 | {
24 | [Optional]
25 | public string Name { get; init; }
26 | [Optional]
27 | public int InternalId { get; init; }
28 |
29 | //Alternative field names.
30 | [Optional]
31 | public string NickNames { get => Name; init => Name = value; }
32 | [Optional]
33 | public int Id { get => InternalId; init => InternalId = value; }
34 | }
35 |
36 | private readonly Trie0 _table = new();
37 |
38 | private static Stream OpenTableFile()
39 | {
40 | if (File.Exists("CharacterAliasTable.csv"))
41 | {
42 | return File.OpenRead("CharacterAliasTable.csv");
43 | }
44 | var res = "PcrBattleChannel.Models.CharacterAliasTable.csv";
45 | return Assembly.GetExecutingAssembly().GetManifestResourceStream(res);
46 | }
47 |
48 | public CharacterAliasProvider()
49 | {
50 | using var stream = OpenTableFile();
51 | var config = new CsvConfiguration(CultureInfo.InvariantCulture)
52 | {
53 | PrepareHeaderForMatch = (header, index) => header.ToLower(),
54 | HeaderValidated = null,
55 | };
56 |
57 | using var reader = new StreamReader(stream);
58 | using var csv = new CsvReader(reader, config);
59 | foreach (var e in csv.GetRecords())
60 | {
61 | foreach (var n in e.Name.Split(',', ' ', '/'))
62 | {
63 | _table.Add(n, e.InternalId);
64 | }
65 | }
66 | }
67 |
68 | public bool TryGet(ref ReadOnlySpan input, out string keyResult, out int idResult)
69 | {
70 | return _table.TryGet(ref input, out keyResult, out idResult);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Models/CharacterConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcrBattleChannel.Models
9 | {
10 | public enum CharacterConfigKind
11 | {
12 | [Display(Name = "无要求")]
13 | Default,
14 | [Display(Name = "星级")]
15 | Rarity,
16 | [Display(Name = "等级")]
17 | Level,
18 | [Display(Name = "装备")]
19 | Rank,
20 | [Display(Name = "专武")]
21 | WeaponLevel,
22 | [Display(Name = "其他")]
23 | Others,
24 | }
25 |
26 | public class CharacterConfig
27 | {
28 | public int CharacterConfigID { get; set; }
29 |
30 | [ForeignKey(nameof(Guild))]
31 | public int GuildID { get; set; }
32 | public Guild Guild { get; set; }
33 |
34 | [ForeignKey(nameof(Character))]
35 | public int CharacterID { get; set; }
36 | public Character Character { get; set; }
37 |
38 | [Display(Name = "分类")]
39 | public CharacterConfigKind Kind { get; set; }
40 |
41 | [Display(Name = "名称")]
42 | public string Name { get; set; }
43 |
44 | [Display(Name = "描述")]
45 | public string Description { get; set; }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Models/ErrorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PcrBattleChannel.Models
4 | {
5 | public class ErrorViewModel
6 | {
7 | public string RequestId { get; set; }
8 |
9 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Models/GlobalData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | public class GlobalData
10 | {
11 | public int GlobalDataID { get; set; }
12 |
13 | [Display(Name = "赛季名称")]
14 | public string SeasonName { get; set; }
15 |
16 | [Display(Name = "开始时间")]
17 | [DataType(DataType.DateTime)]
18 | public DateTime StartTime { get; set; }
19 |
20 | [Display(Name = "结束时间")]
21 | [DataType(DataType.DateTime)]
22 | public DateTime EndTime { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Models/Guild.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Identity;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel.DataAnnotations;
5 | using System.ComponentModel.DataAnnotations.Schema;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace PcrBattleChannel.Models
10 | {
11 | public class Guild
12 | {
13 | public int GuildID { get; set; }
14 |
15 | [Display(Name = "公会名称")]
16 | public string Name { get; set; }
17 |
18 | [Display(Name = "公会简介")]
19 | [DisplayFormat(NullDisplayText = "(空)")]
20 | [DataType(DataType.MultilineText)]
21 | public string Description { get; set; }
22 |
23 | [ForeignKey(nameof(Owner))]
24 | public string OwnerID { get; set; }
25 |
26 | [Display(Name = "会长")]
27 | public PcrIdentityUser Owner { get; set; }
28 |
29 | [Display(Name = "会员")]
30 | public ICollection Members { get; set; }
31 |
32 | public int BossIndex { get; set; }
33 | public float BossDamageRatio { get; set; }
34 |
35 | [DataType(DataType.DateTime)]
36 | [Obsolete("Use memory storage")]
37 | public DateTime LastZhouUpdate { get; set; }
38 |
39 | [Display(Name = "Yobot API地址")]
40 | public string YobotAPI { get; set; }
41 |
42 | public float DamageCoefficient { get; set; }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Models/GuildBossStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | [Obsolete("Use memory storage")]
10 | public class GuildBossStatus
11 | {
12 | public int GuildBossStatusID { get; set; }
13 |
14 | [ForeignKey(nameof(Guild))]
15 | public int GuildID { get; set; }
16 | public Guild Guild { get; set; }
17 |
18 | [ForeignKey(nameof(Boss))]
19 | public int BossID { get; set; }
20 | public Boss Boss { get; set; }
21 |
22 | public int DisplayRow { get; set; }
23 | public int DisplayColumn { get; set; }
24 | public string Name { get; set; } //TODO delete this
25 |
26 | public float DamageRatio { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Models/InMemoryComboListBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | internal class InMemoryComboListBuilder
10 | {
11 | private InMemoryGuild _guild;
12 | private readonly Dictionary<(int, int, int), int> _bossMap = new();
13 | private readonly List> _comboData = new();
14 | private int _comboDataCount;
15 |
16 | public int ZhouCount { get; private set; }
17 | public int GroupCount => _comboDataCount;
18 |
19 | public IEnumerable<(int, InMemoryComboBorrowInfo)> GetGroup(int index)
20 | {
21 | return _comboData[index];
22 | }
23 |
24 | public void Reset(InMemoryGuild guild, int zhouCount)
25 | {
26 | _guild = guild;
27 | foreach (var list in _comboData)
28 | {
29 | list.Clear();
30 | }
31 | _bossMap.Clear();
32 | _comboDataCount = 0;
33 | ZhouCount = zhouCount;
34 | }
35 |
36 | public void AddCombo(int z1, int z2, int z3, InMemoryComboBorrowInfo[] borrowInfo)
37 | {
38 | var bossID = (_guild.GetZhouVariantByIndex(z1)?.BossID ?? 0,
39 | _guild.GetZhouVariantByIndex(z2)?.BossID ?? 0,
40 | _guild.GetZhouVariantByIndex(z3)?.BossID ?? 0);
41 | if (!_bossMap.TryGetValue(bossID, out var index))
42 | {
43 | index = _comboDataCount++;
44 | _bossMap.Add(bossID, index);
45 | if (_comboData.Count == index)
46 | {
47 | _comboData.Add(new());
48 | }
49 | }
50 | if (ZhouCount > 0) _comboData[index].Add((z1, borrowInfo[0]));
51 | if (ZhouCount > 1) _comboData[index].Add((z2, borrowInfo[1]));
52 | if (ZhouCount > 2) _comboData[index].Add((z3, borrowInfo[2]));
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Models/InMemoryZhouVariant.cs:
--------------------------------------------------------------------------------
1 | using PcrBattleChannel.Data;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Collections.Immutable;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcrBattleChannel.Models
9 | {
10 | //default of this struct is used for new user.
11 | public struct InMemoryUserZhouVariantData
12 | {
13 | //0: invalid, 1-5: borrow, 6: no borrow.
14 | public byte BorrowPlusOne;
15 | }
16 |
17 | //Track a ZhouVariant entry in database.
18 | public class InMemoryZhouVariant
19 | {
20 | public InMemoryGuild Owner { get; init; }
21 | public int Index { get; init; }
22 | public int ZhouID { get; init; }
23 | public int ZhouVariantID { get; init; }
24 | public bool IsDraft { get; init; }
25 |
26 | public int BossID { get; init; }
27 | public int Damage { get; init; }
28 |
29 | public ImmutableArray CharacterIDs { get; init; }
30 | public ImmutableDictionary CharacterIndexMap { get; init; } //Used in borrow case calculation.
31 |
32 | //character index -> group index -> ccid[]
33 | public ImmutableArray>> CharacterConfigIDs { get; init; }
34 |
35 | public InMemoryUserZhouVariantData[] UserData { get; init; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Models/InitCharacterData.csv:
--------------------------------------------------------------------------------
1 | InternalID,Name,Rarity,HasWeapon,Range
2 | 1001,日和,1,1,200
3 | 1002,优衣,1,1,800
4 | 1003,怜,1,1,250
5 | 1004,禊,1,0,205
6 | 1005,茉莉,2,0,185
7 | 1006,茜里,2,1,570
8 | 1007,宫子,2,0,125
9 | 1008,雪,2,0,805
10 | 1009,杏奈,3,0,440
11 | 1010,真步,3,0,795
12 | 1011,璃乃,3,0,700
13 | 1012,初音,3,0,755
14 | 1013,七七香,2,0,740
15 | 1014,香澄,3,0,730
16 | 1015,美里,2,0,735
17 | 1016,铃奈,2,0,705
18 | 1017,香织,2,0,145
19 | 1018,伊绪,3,0,715
20 | 1020,美美,2,0,360
21 | 1021,胡桃,1,1,240
22 | 1022,依里,1,1,575
23 | 1023,绫音,2,0,210
24 | 1025,铃莓,1,0,720
25 | 1026,铃,2,0,550
26 | 1027,惠理子,2,1,230
27 | 1028,咲恋,3,1,430
28 | 1029,望,3,1,160
29 | 1030,妮诺,3,1,415
30 | 1031,忍,2,1,365
31 | 1032,秋乃,3,1,180
32 | 1033,真阳,2,0,395
33 | 1034,优花梨,1,1,405
34 | 1036,镜华,3,0,810
35 | 1037,智,3,0,220
36 | 1038,栞,2,0,710
37 | 1040,碧,1,0,785
38 | 1042,千歌,2,0,790
39 | 1043,真琴,3,0,165
40 | 1044,伊莉亚,3,0,425
41 | 1045,空花,2,0,130
42 | 1046,珠希,2,1,215
43 | 1047,纯,3,0,135
44 | 1048,美冬,2,1,420
45 | 1049,静流,3,1,285
46 | 1050,美咲,1,0,760
47 | 1051,深月,2,0,565
48 | 1052,莉玛,1,0,105
49 | 1053,莫妮卡,3,0,410
50 | 1054,纺希,2,0,195
51 | 1055,步美,1,0,510
52 | 1056,流夏,3,0,158
53 | 1057,吉塔,3,0,245
54 | 1058,贪吃佩可,1,1,155
55 | 1059,可可萝,1,1,500
56 | 1060,凯留,1,1,750
57 | 1061,矛依未,3,0,162
58 | 1063,亚里莎,3,1,625
59 | 1071,克莉丝提娜,3,0,290
60 | 1075,贪吃佩可(夏日),3,0,235
61 | 1076,可可萝(夏日),1,0,535
62 | 1077,铃莓(夏日),3,0,775
63 | 1078,凯留(夏日),3,0,780
64 | 1079,珠希(夏日),3,0,225
65 | 1080,美冬(夏日),1,0,495
66 | 1081,忍(万圣节),3,0,440
67 | 1082,宫子(万圣节),1,0,590
68 | 1083,美咲(万圣节),3,0,815
69 | 1084,千歌(圣诞节),3,0,770
70 | 1085,胡桃(圣诞节),1,0,295
71 | 1086,绫音(圣诞节),3,0,190
72 | 1087,日和(新年),3,0,170
73 | 1088,优衣(新年),3,0,745
74 | 1089,怜(新年),1,0,153
75 | 1090,惠理子(情人节),1,0,187
76 | 1091,静流(情人节),3,0,385
77 | 1701,环奈,3,0,433
--------------------------------------------------------------------------------
/Models/ModelDisplayExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Html;
2 | using Microsoft.AspNetCore.Mvc.Rendering;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Web;
8 |
9 | namespace PcrBattleChannel.Models
10 | {
11 | public static class ModelDisplayExtensions
12 | {
13 | public static IHtmlContent DisplayCharacterName(this IHtmlHelper html, string val)
14 | {
15 | var ret = new HtmlContentBuilder();
16 | var index = val.IndexOf('(');
17 | if (index == -1)
18 | {
19 | ret.AppendHtml(HttpUtility.HtmlEncode(val));
20 | }
21 | else
22 | {
23 | ret.AppendHtml(@"");
24 | ret.AppendHtml(HttpUtility.HtmlEncode(val[0..index]));
25 | ret.AppendHtml("");
26 | ret.AppendHtml(@"");
27 | ret.AppendHtml(HttpUtility.HtmlEncode(val[index..]));
28 | ret.AppendHtml("");
29 | }
30 | return ret;
31 | }
32 |
33 | public static string ToDamageString(this int damage)
34 | {
35 | if (damage > 1E9f)
36 | {
37 | return (damage / 1E9f).ToString("0.00") + " G";
38 | }
39 | else if (damage > 1E6f)
40 | {
41 | return (damage / 1E6f).ToString("0.00") + " M";
42 | }
43 | else if (damage > 1E3f)
44 | {
45 | return (damage / 1E3f).ToString("0.00") + " K";
46 | }
47 | return damage.ToString();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Models/PcrIdentityUser.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Identity;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcrBattleChannel.Models
9 | {
10 | public class PcrIdentityUser : IdentityUser
11 | {
12 | public string GameID { get; set; }
13 | public ulong QQID { get; set; }
14 | public bool DisableYobotSync { get; set; }
15 |
16 | public int? GuildID { get; set; }
17 | public Guild Guild { get; set; }
18 | public bool IsGuildAdmin { get; set; }
19 |
20 | //TODO some of these navigation collections are not used
21 |
22 | public ICollection CharacterStatuses { get; set; }
23 | public int Attempts { get; set; }
24 | public int GuessedAttempts { get; set; } //Number of attempts that are from guessing.
25 |
26 | //Mark that YobotSync cannot decide user's state. So the user's attempts and combos
27 | //are inaccurate and should not be included in value optimization.
28 | public bool IsIgnored { get; set; }
29 |
30 | public bool ComboIncludesDrafts { get; set; }
31 |
32 | //Attempts
33 |
34 | [ForeignKey(nameof(Attempt1))]
35 | public int? Attempt1ID { get; set; }
36 | public ZhouVariant Attempt1 { get; set; }
37 | public int? Attempt1Borrow { get; set; }
38 |
39 | [ForeignKey(nameof(Attempt2))]
40 | public int? Attempt2ID { get; set; }
41 | public ZhouVariant Attempt2 { get; set; }
42 | public int? Attempt2Borrow { get; set; }
43 |
44 | [ForeignKey(nameof(Attempt3))]
45 | public int? Attempt3ID { get; set; }
46 | public ZhouVariant Attempt3 { get; set; }
47 | public int? Attempt3Borrow { get; set; }
48 |
49 | public DateTime LastConfirm { get; set; }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Models/StandardConfigNames.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | public static class StandardConfigNames
10 | {
11 | public static readonly (Regex regex, CharacterConfigKind kind)[] Values = new[]
12 | {
13 | (new Regex("\\G[123456]星"), CharacterConfigKind.Rarity),
14 | (new Regex("\\G[Rr]\\d+-[0123456Xx]"), CharacterConfigKind.Rank),
15 | (new Regex("\\G开专"), CharacterConfigKind.WeaponLevel),
16 | (new Regex("\\G满专"), CharacterConfigKind.WeaponLevel),
17 | };
18 |
19 | public static readonly (string regex, string example)[] FrontEndRegexCheck = new[]
20 | {
21 | ("a^", ""),
22 | ("^[123456]星$", "“4星”、“5星”"),
23 | (".*", ""),
24 | ("^[R]\\d+-[0123456X]$", "“R9-6”、“R11-3”、“R11-X”"),
25 | (".*", ""),
26 | (".*", ""),
27 | };
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Models/UserCharacterConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcrBattleChannel.Models
9 | {
10 | //Many-to-many relationship between PcrIdentityUser and CharacterConfig.
11 | public class UserCharacterConfig
12 | {
13 | public int UserCharacterConfigID { get; set; }
14 |
15 | [ForeignKey(nameof(User))]
16 | [Required]
17 | public string UserID { get; set; }
18 | public PcrIdentityUser User { get; set; }
19 |
20 | [ForeignKey(nameof(CharacterConfig))]
21 | public int CharacterConfigID { get; set; }
22 | public CharacterConfig CharacterConfig { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Models/UserCharacterStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | public class UserCharacterStatus
10 | {
11 | public int UserCharacterStatusID { get; set; }
12 |
13 | [ForeignKey(nameof(User))]
14 | public string UserID { get; set; }
15 | public PcrIdentityUser User { get; set; }
16 |
17 | [ForeignKey(nameof(Character))]
18 | public int CharacterID { get; set; }
19 | public Character Character { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Models/Zhou.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcrBattleChannel.Models
9 | {
10 | //'轴'! This is the best translation!
11 | public class Zhou
12 | {
13 | public int ZhouID { get; set; }
14 |
15 | [ForeignKey(nameof(Guild))]
16 | public int GuildID { get; set; }
17 | public Guild Guild { get; set; }
18 |
19 | [Display(Name = "轴名")]
20 | public string Name { get; set; }
21 |
22 | [Display(Name = "说明")]
23 | [DataType(DataType.MultilineText)]
24 | [DisplayFormat(NullDisplayText = "(无)")]
25 | public string Description { get; set; }
26 |
27 | [ForeignKey(nameof(Boss))]
28 | public int BossID { get; set; }
29 | [Display(Name = "Boss")]
30 | public Boss Boss { get; set; }
31 |
32 | [ForeignKey(nameof(C1))]
33 | public int? C1ID { get; set; }
34 | public Character C1 { get; set; }
35 |
36 | [ForeignKey(nameof(C2))]
37 | public int? C2ID { get; set; }
38 | public Character C2 { get; set; }
39 |
40 | [ForeignKey(nameof(C3))]
41 | public int? C3ID { get; set; }
42 | public Character C3 { get; set; }
43 |
44 | [ForeignKey(nameof(C4))]
45 | public int? C4ID { get; set; }
46 | public Character C4 { get; set; }
47 |
48 | [ForeignKey(nameof(C5))]
49 | public int? C5ID { get; set; }
50 | public Character C5 { get; set; }
51 |
52 | public ICollection Variants { get; set; }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Models/ZhouVariant.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace PcrBattleChannel.Models
9 | {
10 | public class ZhouVariant
11 | {
12 | public int ZhouVariantID { get; set; }
13 |
14 | [ForeignKey(nameof(Zhou))]
15 | public int ZhouID { get; set; }
16 | public Zhou Zhou { get; set; }
17 |
18 | [Display(Name = "配置名")]
19 | public string Name { get; set; }
20 |
21 | [DataType(DataType.MultilineText)]
22 | [Display(Name = "文字轴")]
23 | public string Content { get; set; }
24 |
25 | [Display(Name = "发布为草稿")]
26 | public bool IsDraft { get; set; }
27 |
28 | [Display(Name = "平均伤害")]
29 | public int Damage { get; set; }
30 |
31 | public ICollection CharacterConfigs { get; set; }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Models/ZhouVariantCharacterConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace PcrBattleChannel.Models
8 | {
9 | //Many-to-many relationship between ZhouVariant and CharacterConfig.
10 | public class ZhouVariantCharacterConfig
11 | {
12 | public int ZhouVariantCharacterConfigID { get; set; }
13 |
14 | [ForeignKey(nameof(ZhouVariant))]
15 | public int ZhouVariantID { get; set; }
16 | public ZhouVariant ZhouVariant { get; set; }
17 |
18 | [ForeignKey(nameof(CharacterConfig))]
19 | public int? CharacterConfigID { get; set; }
20 | public CharacterConfig CharacterConfig { get; set; }
21 |
22 | //0-4 for the 5 characters.
23 | public int CharacterIndex { get; set; }
24 |
25 | //Configs with same group index will be or'ed together first, and then
26 | //all groups are and'ed together.
27 | //This can be automatically decided by CharacterConfig.Kind.
28 | public int OrGroupIndex { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Pages/Admin/AddGuild.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model PcrBattleChannel.Pages.Admin.AddGuildModel
3 | @{
4 | ViewData["Title"] = "创建公会";
5 | }
6 |
7 |