Initial Commit

dashboard
Pat Hartl 2023-01-02 15:44:04 -06:00
parent 9c7d6e8432
commit 38212521af
152 changed files with 80669 additions and 0 deletions

1
.gitignore vendored
View File

@ -348,3 +348,4 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
Upload/

View File

@ -0,0 +1,10 @@
@page
@model AccessDeniedModel
@{
ViewData["Title"] = "Access denied";
}
<header>
<h1 class="text-danger">@ViewData["Title"]</h1>
<p class="text-danger">You do not have access to this resource.</p>
</header>

View File

@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LANCommander.Areas.Identity.Pages.Account
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class AccessDeniedModel : PageModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public void OnGet()
{
}
}
}

View File

@ -0,0 +1,26 @@
@page
@model ForgotPasswordModel
@{
ViewData["Title"] = "Forgot your password?";
}
<h1>@ViewData["Title"]</h1>
<h2>Enter your email.</h2>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-floating">
<input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" />
<label asp-for="Input.Email" class="form-label"></label>
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Reset Password</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -0,0 +1,85 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace LANCommander.Areas.Identity.Pages.Account
{
public class ForgotPasswordModel : PageModel
{
private readonly UserManager<User> _userManager;
private readonly IEmailSender _emailSender;
public ForgotPasswordModel(UserManager<User> userManager, IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[EmailAddress]
public string Email { get; set; }
}
public async Task<IActionResult> OnPostAsync()
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(Input.Email);
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return RedirectToPage("./ForgotPasswordConfirmation");
}
// For more information on how to enable account confirmation and password reset please
// visit https://go.microsoft.com/fwlink/?LinkID=532713
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ResetPassword",
pageHandler: null,
values: new { area = "Identity", code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
Input.Email,
"Reset Password",
$"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
return RedirectToPage("./ForgotPasswordConfirmation");
}
return Page();
}
}
}

View File

@ -0,0 +1,85 @@
@page
@model LoginModel
@{
ViewData["Title"] = "Log in";
}
<h1>@ViewData["Title"]</h1>
<div class="row">
<div class="col-md-4">
<section>
<form id="account" method="post">
<h2>Use a local account to log in.</h2>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-floating">
<input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" />
<label asp-for="Input.Email" class="form-label"></label>
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" />
<label asp-for="Input.Password" class="form-label"></label>
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div>
<div class="checkbox">
<label asp-for="Input.RememberMe" class="form-label">
<input class="form-check-input" asp-for="Input.RememberMe" />
@Html.DisplayNameFor(m => m.Input.RememberMe)
</label>
</div>
</div>
<div>
<button id="login-submit" type="submit" class="w-100 btn btn-lg btn-primary">Log in</button>
</div>
<div>
<p>
<a id="forgot-password" asp-page="./ForgotPassword">Forgot your password?</a>
</p>
<p>
<a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
</p>
<p>
<a id="resend-confirmation" asp-page="./ResendEmailConfirmation">Resend email confirmation</a>
</p>
</div>
</form>
</section>
</div>
<div class="col-md-6 col-md-offset-2">
<section>
<h3>Use another service to log in.</h3>
<hr />
@{
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{
<div>
<p>
There are no external authentication services configured. See this <a href="https://go.microsoft.com/fwlink/?LinkID=532715">article
about setting up this ASP.NET application to support logging in via external services</a>.
</p>
</div>
}
else
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in Model.ExternalLogins)
{
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
</section>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -0,0 +1,141 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace LANCommander.Areas.Identity.Pages.Account
{
public class LoginModel : PageModel
{
private readonly SignInManager<User> _signInManager;
private readonly ILogger<LoginModel> _logger;
public LoginModel(SignInManager<User> signInManager, ILogger<LoginModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public IList<AuthenticationScheme> ExternalLogins { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string ReturnUrl { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[TempData]
public string ErrorMessage { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[EmailAddress]
public string Email { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
public async Task OnGetAsync(string returnUrl = null)
{
if (!string.IsNullOrEmpty(ErrorMessage))
{
ModelState.AddModelError(string.Empty, ErrorMessage);
}
returnUrl ??= Url.Content("~/");
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
}
}

View File

@ -0,0 +1,21 @@
@page
@model LogoutModel
@{
ViewData["Title"] = "Log out";
}
<header>
<h1>@ViewData["Title"]</h1>
@{
if (User.Identity.IsAuthenticated)
{
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Page("/", new { area = "" })" method="post">
<button type="submit" class="nav-link btn btn-link text-dark">Click here to Logout</button>
</form>
}
else
{
<p>You have successfully logged out of the application.</p>
}
}
</header>

View File

@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace LANCommander.Areas.Identity.Pages.Account
{
public class LogoutModel : PageModel
{
private readonly SignInManager<User> _signInManager;
private readonly ILogger<LogoutModel> _logger;
public LogoutModel(SignInManager<User> signInManager, ILogger<LogoutModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public async Task<IActionResult> OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
if (returnUrl != null)
{
return LocalRedirect(returnUrl);
}
else
{
// This needs to be a redirect so that the browser performs a new
// request and the identity for the user gets updated.
return RedirectToPage();
}
}
}
}

View File

@ -0,0 +1,36 @@
@page
@model ChangePasswordModel
@{
ViewData["Title"] = "Change password";
ViewData["ActivePage"] = ManageNavPages.ChangePassword;
}
<h3>@ViewData["Title"]</h3>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
<div class="col-md-6">
<form id="change-password-form" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-floating">
<input asp-for="Input.OldPassword" class="form-control" autocomplete="current-password" aria-required="true" />
<label asp-for="Input.OldPassword" class="form-label"></label>
<span asp-validation-for="Input.OldPassword" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.NewPassword" class="form-control" autocomplete="new-password" aria-required="true" />
<label asp-for="Input.NewPassword" class="form-label"></label>
<span asp-validation-for="Input.NewPassword" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" />
<label asp-for="Input.ConfirmPassword" class="form-label"></label>
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Update password</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -0,0 +1,128 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace LANCommander.Areas.Identity.Pages.Account.Manage
{
public class ChangePasswordModel : PageModel
{
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;
private readonly ILogger<ChangePasswordModel> _logger;
public ChangePasswordModel(
UserManager<User> userManager,
SignInManager<User> signInManager,
ILogger<ChangePasswordModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[TempData]
public string StatusMessage { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[DataType(DataType.Password)]
[Display(Name = "Current password")]
public string OldPassword { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var hasPassword = await _userManager.HasPasswordAsync(user);
if (!hasPassword)
{
return RedirectToPage("./SetPassword");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var changePasswordResult = await _userManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword);
if (!changePasswordResult.Succeeded)
{
foreach (var error in changePasswordResult.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return Page();
}
await _signInManager.RefreshSignInAsync(user);
_logger.LogInformation("User changed their password successfully.");
StatusMessage = "Your password has been changed.";
return RedirectToPage();
}
}
}

View File

@ -0,0 +1,30 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Profile";
ViewData["ActivePage"] = ManageNavPages.Index;
}
<h3>@ViewData["Title"]</h3>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
<div class="col-md-6">
<form id="profile-form" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-floating">
<input asp-for="Username" class="form-control" disabled />
<label asp-for="Username" class="form-label"></label>
</div>
<div class="form-floating">
<input asp-for="Input.PhoneNumber" class="form-control" />
<label asp-for="Input.PhoneNumber" class="form-label"></label>
<span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
</div>
<button id="update-profile-button" type="submit" class="w-100 btn btn-lg btn-primary">Save</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -0,0 +1,119 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LANCommander.Areas.Identity.Pages.Account.Manage
{
public class IndexModel : PageModel
{
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;
public IndexModel(
UserManager<User> userManager,
SignInManager<User> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string Username { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[TempData]
public string StatusMessage { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Phone]
[Display(Name = "Phone number")]
public string PhoneNumber { get; set; }
}
private async Task LoadAsync(User user)
{
var userName = await _userManager.GetUserNameAsync(user);
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
Username = userName;
Input = new InputModel
{
PhoneNumber = phoneNumber
};
}
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
await LoadAsync(user);
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadAsync(user);
return Page();
}
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
if (Input.PhoneNumber != phoneNumber)
{
var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
if (!setPhoneResult.Succeeded)
{
StatusMessage = "Unexpected error when trying to set phone number.";
return RedirectToPage();
}
}
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Your profile has been updated";
return RedirectToPage();
}
}
}

View File

@ -0,0 +1,123 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace LANCommander.Areas.Identity.Pages.Account.Manage
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static class ManageNavPages
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string Index => "Index";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string Email => "Email";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string ChangePassword => "ChangePassword";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string DownloadPersonalData => "DownloadPersonalData";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string DeletePersonalData => "DeletePersonalData";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string ExternalLogins => "ExternalLogins";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string PersonalData => "PersonalData";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string TwoFactorAuthentication => "TwoFactorAuthentication";
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string EmailNavClass(ViewContext viewContext) => PageNavClass(viewContext, Email);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string ChangePasswordNavClass(ViewContext viewContext) => PageNavClass(viewContext, ChangePassword);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string DownloadPersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DownloadPersonalData);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string DeletePersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DeletePersonalData);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string ExternalLoginsNavClass(ViewContext viewContext) => PageNavClass(viewContext, ExternalLogins);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string PersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, PersonalData);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication);
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string PageNavClass(ViewContext viewContext, string page)
{
var activePage = viewContext.ViewData["ActivePage"] as string
?? System.IO.Path.GetFileNameWithoutExtension(viewContext.ActionDescriptor.DisplayName);
return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null;
}
}
}

View File

@ -0,0 +1,35 @@
@page
@model SetPasswordModel
@{
ViewData["Title"] = "Set password";
ViewData["ActivePage"] = ManageNavPages.ChangePassword;
}
<h3>Set your password</h3>
<partial name="_StatusMessage" for="StatusMessage" />
<p class="text-info">
You do not have a local username/password for this site. Add a local
account so you can log in without an external login.
</p>
<div class="row">
<div class="col-md-6">
<form id="set-password-form" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-floating">
<input asp-for="Input.NewPassword" class="form-control" autocomplete="new-password" />
<label asp-for="Input.NewPassword" class="form-label"></label>
<span asp-validation-for="Input.NewPassword" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" />
<label asp-for="Input.ConfirmPassword" class="form-label"></label>
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Set password</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -0,0 +1,115 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LANCommander.Areas.Identity.Pages.Account.Manage
{
public class SetPasswordModel : PageModel
{
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;
public SetPasswordModel(
UserManager<User> userManager,
SignInManager<User> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[TempData]
public string StatusMessage { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var hasPassword = await _userManager.HasPasswordAsync(user);
if (hasPassword)
{
return RedirectToPage("./ChangePassword");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var addPasswordResult = await _userManager.AddPasswordAsync(user, Input.NewPassword);
if (!addPasswordResult.Succeeded)
{
foreach (var error in addPasswordResult.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return Page();
}
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Your password has been set.";
return RedirectToPage();
}
}
}

View File

@ -0,0 +1,29 @@
@{
if (ViewData.TryGetValue("ParentLayout", out var parentLayout))
{
Layout = (string)parentLayout;
}
else
{
Layout = "/Areas/Identity/Pages/_Layout.cshtml";
}
}
<h1>Manage your account</h1>
<div>
<h2>Change your account settings</h2>
<hr />
<div class="row">
<div class="col-md-3">
<partial name="_ManageNav" />
</div>
<div class="col-md-9">
@RenderBody()
</div>
</div>
</div>
@section Scripts {
@RenderSection("Scripts", required: false)
}

View File

@ -0,0 +1,15 @@
@inject SignInManager<User> SignInManager
@{
var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<ul class="nav nav-pills flex-column">
<li class="nav-item"><a class="nav-link @ManageNavPages.IndexNavClass(ViewContext)" id="profile" asp-page="./Index">Profile</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.EmailNavClass(ViewContext)" id="email" asp-page="./Email">Email</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)" id="change-password" asp-page="./ChangePassword">Password</a></li>
@if (hasExternalLogins)
{
<li id="external-logins" class="nav-item"><a id="external-login" class="nav-link @ManageNavPages.ExternalLoginsNavClass(ViewContext)" asp-page="./ExternalLogins">External logins</a></li>
}
<li class="nav-item"><a class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)" id="two-factor" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)" id="personal-data" asp-page="./PersonalData">Personal data</a></li>
</ul>

View File

@ -0,0 +1 @@
@using LANCommander.Areas.Identity.Pages.Account.Manage

View File

@ -0,0 +1,67 @@
@page
@model RegisterModel
@{
ViewData["Title"] = "Register";
}
<h1>@ViewData["Title"]</h1>
<div class="row">
<div class="col-md-4">
<form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
<h2>Create a new account.</h2>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-floating">
<input asp-for="Input.Username" class="form-control" autocomplete="username" aria-required="true" />
<label asp-for="Input.Username"></label>
<span asp-validation-for="Input.Username" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" />
<label asp-for="Input.Password"></label>
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" />
<label asp-for="Input.ConfirmPassword"></label>
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
</form>
</div>
<div class="col-md-6 col-md-offset-2">
<section>
<h3>Use another service to register.</h3>
<hr />
@{
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{
<div>
<p>
There are no external authentication services configured. See this <a href="https://go.microsoft.com/fwlink/?LinkID=532715">article
about setting up this ASP.NET application to support logging in via external services</a>.
</p>
</div>
}
else
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in Model.ExternalLogins)
{
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
</section>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -0,0 +1,158 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
namespace LANCommander.Areas.Identity.Pages.Account
{
public class RegisterModel : PageModel
{
private readonly SignInManager<User> _signInManager;
private readonly UserManager<User> _userManager;
private readonly IUserStore<User> _userStore;
private readonly IUserEmailStore<User> _emailStore;
private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender;
public RegisterModel(
UserManager<User> userManager,
IUserStore<User> userStore,
SignInManager<User> signInManager,
ILogger<RegisterModel> logger,
IEmailSender emailSender)
{
_userManager = userManager;
_userStore = userStore;
_signInManager = signInManager;
_logger = logger;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string ReturnUrl { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public IList<AuthenticationScheme> ExternalLogins { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[Display(Name = "Username")]
public string Username { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public async Task OnGetAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = CreateUser();
await _userStore.SetUserNameAsync(user, Input.Username, CancellationToken.None);
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
private User CreateUser()
{
try
{
return Activator.CreateInstance<User>();
}
catch
{
throw new InvalidOperationException($"Can't create an instance of '{nameof(User)}'. " +
$"Ensure that '{nameof(User)}' is not an abstract class and has a parameterless constructor, or alternatively " +
$"override the register page in /Areas/Identity/Pages/Account/Register.cshtml");
}
}
}
}

View File

@ -0,0 +1,37 @@
@page
@model ResetPasswordModel
@{
ViewData["Title"] = "Reset password";
}
<h1>@ViewData["Title"]</h1>
<h2>Reset your password.</h2>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input asp-for="Input.Code" type="hidden" />
<div class="form-floating">
<input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" />
<label asp-for="Input.Email" class="form-label"></label>
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" />
<label asp-for="Input.Password" class="form-label"></label>
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-floating">
<input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" />
<label asp-for="Input.ConfirmPassword" class="form-label"></label>
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Reset</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

View File

@ -0,0 +1,118 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace LANCommander.Areas.Identity.Pages.Account
{
public class ResetPasswordModel : PageModel
{
private readonly UserManager<User> _userManager;
public ResetPasswordModel(UserManager<User> userManager)
{
_userManager = userManager;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[BindProperty]
public InputModel Input { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class InputModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[EmailAddress]
public string Email { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
public string Password { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
public string Code { get; set; }
}
public IActionResult OnGet(string code = null)
{
if (code == null)
{
return BadRequest("A code must be supplied for password reset.");
}
else
{
Input = new InputModel
{
Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code))
};
return Page();
}
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _userManager.FindByEmailAsync(Input.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return RedirectToPage("./ResetPasswordConfirmation");
}
var result = await _userManager.ResetPasswordAsync(user, Input.Code, Input.Password);
if (result.Succeeded)
{
return RedirectToPage("./ResetPasswordConfirmation");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return Page();
}
}
}

View File

@ -0,0 +1,10 @@
@page
@model ResetPasswordConfirmationModel
@{
ViewData["Title"] = "Reset password confirmation";
}
<h1>@ViewData["Title"]</h1>
<p>
Your password has been reset. Please <a asp-page="./Login">click here to log in</a>.
</p>

View File

@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LANCommander.Areas.Identity.Pages.Account
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[AllowAnonymous]
public class ResetPasswordConfirmationModel : PageModel
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public void OnGet()
{
}
}
}

View File

@ -0,0 +1 @@
@using LANCommander.Areas.Identity.Pages.Account

View File

@ -0,0 +1,18 @@
<environment include="Development">
<script src="~/Identity/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"
asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator"
crossorigin="anonymous"
integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"
asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
crossorigin="anonymous"
integrity="sha384-R3vNCHsZ+A2Lo3d5A6XNP7fdQkeswQWTIPfiYwSpEP3YV079R+93YzTeZRah7f/F">
</script>
</environment>

View File

@ -0,0 +1,5 @@
@using Microsoft.AspNetCore.Identity
@using LANCommander.Areas.Identity
@using LANCommander.Areas.Identity.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using LANCommander.Data.Models

View File

@ -0,0 +1,3 @@
@{
Layout = "/Views/Shared/_Layout.cshtml";
}

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using LANCommander.Data;
using LANCommander.Data.Models;
namespace LANCommander.Controllers
{
public class CompaniesController : Controller
{
private readonly DatabaseContext _context;
public CompaniesController(DatabaseContext context)
{
_context = context;
}
// GET: Companies
public async Task<IActionResult> Index()
{
return _context.Companies != null ?
View(await _context.Companies.ToListAsync()) :
Problem("Entity set 'DatabaseContext.Companies' is null.");
}
// GET: Companies/Details/5
public async Task<IActionResult> Details(Guid? id)
{
if (id == null || _context.Companies == null)
{
return NotFound();
}
var company = await _context.Companies
.FirstOrDefaultAsync(m => m.Id == id);
if (company == null)
{
return NotFound();
}
return View(company);
}
// GET: Companies/Create
public IActionResult Create()
{
return View();
}
// POST: Companies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Name,Id,CreatedOn,CreatedById,UpdatedOn,UpdatedById")] Company company)
{
if (ModelState.IsValid)
{
company.Id = Guid.NewGuid();
_context.Add(company);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(company);
}
// GET: Companies/Edit/5
public async Task<IActionResult> Edit(Guid? id)
{
if (id == null || _context.Companies == null)
{
return NotFound();
}
var company = await _context.Companies.FindAsync(id);
if (company == null)
{
return NotFound();
}
return View(company);
}
// POST: Companies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(Guid id, [Bind("Name,Id,CreatedOn,CreatedById,UpdatedOn,UpdatedById")] Company company)
{
if (id != company.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(company);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CompanyExists(company.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(company);
}
// GET: Companies/Delete/5
public async Task<IActionResult> Delete(Guid? id)
{
if (id == null || _context.Companies == null)
{
return NotFound();
}
var company = await _context.Companies
.FirstOrDefaultAsync(m => m.Id == id);
if (company == null)
{
return NotFound();
}
return View(company);
}
// POST: Companies/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(Guid id)
{
if (_context.Companies == null)
{
return Problem("Entity set 'DatabaseContext.Companies' is null.");
}
var company = await _context.Companies.FindAsync(id);
if (company != null)
{
_context.Companies.Remove(company);
}
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool CompanyExists(Guid id)
{
return (_context.Companies?.Any(e => e.Id == id)).GetValueOrDefault();
}
}
}

View File

@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using LANCommander.Data;
using LANCommander.Data.Models;
namespace LANCommander.Controllers
{
public class GamesController : Controller
{
private readonly DatabaseContext Context;
public GamesController(DatabaseContext context)
{
Context = context;
}
// GET: Games
public async Task<IActionResult> Index()
{
return Context.Games != null ?
View(await Context.Games.ToListAsync()) :
Problem("Entity set 'DatabaseContext.Games' is null.");
}
// GET: Games/Details/5
public async Task<IActionResult> Details(Guid? id)
{
if (id == null || Context.Games == null)
{
return NotFound();
}
var game = await Context.Games
.FirstOrDefaultAsync(m => m.Id == id);
if (game == null)
{
return NotFound();
}
return View(game);
}
// GET: Games/Create
public IActionResult Create()
{
return View();
}
// POST: Games/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Title,SortTitle,Description,ReleasedOn,Id,CreatedOn,CreatedById,UpdatedOn,UpdatedById")] Game game)
{
if (ModelState.IsValid)
{
using (Repository<Game> repo = new Repository<Game>(Context, HttpContext))
{
await repo.Add(game);
await repo.SaveChanges();
}
return RedirectToAction(nameof(Index));
}
return View(game);
}
// GET: Games/Edit/5
public async Task<IActionResult> Edit(Guid? id)
{
Game game;
if (id == null || Context.Games == null)
{
return NotFound();
}
using (Repository<Game> repo = new Repository<Game>(Context, HttpContext))
{
game = await repo.Find(id.GetValueOrDefault());
if (game == null)
return NotFound();
}
return View(game);
}
// POST: Games/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(Guid id, [Bind("Title,SortTitle,Description,ReleasedOn,Id,CreatedOn,CreatedById,UpdatedOn,UpdatedById")] Game game)
{
if (id != game.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
using (Repository<Game> repo = new Repository<Game>(Context, HttpContext))
{
repo.Update(game);
await repo.SaveChanges();
}
}
catch (DbUpdateConcurrencyException)
{
if (!GameExists(game.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(game);
}
// GET: Games/Delete/5
public async Task<IActionResult> Delete(Guid? id)
{
if (id == null || Context.Games == null)
{
return NotFound();
}
var game = await Context.Games
.FirstOrDefaultAsync(m => m.Id == id);
if (game == null)
{
return NotFound();
}
return View(game);
}
// POST: Games/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(Guid id)
{
if (Context.Games == null)
{
return Problem("Entity set 'DatabaseContext.Games' is null.");
}
var game = await Context.Games.FindAsync(id);
if (game != null)
{
Context.Games.Remove(game);
}
await Context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
public async Task<IActionResult> AddArchive(Guid? id)
{
if (id == null || Context.Games == null)
return NotFound();
using (Repository<Game> repo = new Repository<Game>(Context, HttpContext))
{
var game = await repo.Find(id.GetValueOrDefault());
Archive lastVersion = null;
if (game.Archives != null && game.Archives.Count > 0)
lastVersion = game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault();
return View(new Archive()
{
Game = game,
LastVersion = lastVersion,
});
}
}
[HttpPost]
public IActionResult AddArchive([Bind("UploadedFile", "Version")] Archive archive)
{
return RedirectToAction(nameof(Index));
}
private bool GameExists(Guid id)
{
return (Context.Games?.Any(e => e.Id == id)).GetValueOrDefault();
}
}
}

View File

@ -0,0 +1,32 @@
using LANCommander.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace LANCommander.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using LANCommander.Data;
using LANCommander.Data.Models;
namespace LANCommander.Controllers
{
public class TagsController : Controller
{
private readonly DatabaseContext _context;
public TagsController(DatabaseContext context)
{
_context = context;
}
// GET: Tags
public async Task<IActionResult> Index()
{
return _context.Tags != null ?
View(await _context.Tags.ToListAsync()) :
Problem("Entity set 'DatabaseContext.Tags' is null.");
}
// GET: Tags/Details/5
public async Task<IActionResult> Details(Guid? id)
{
if (id == null || _context.Tags == null)
{
return NotFound();
}
var tag = await _context.Tags
.FirstOrDefaultAsync(m => m.Id == id);
if (tag == null)
{
return NotFound();
}
return View(tag);
}
// GET: Tags/Create
public IActionResult Create()
{
return View();
}
// POST: Tags/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Name,Id,CreatedOn,CreatedById,UpdatedOn,UpdatedById")] Tag tag)
{
if (ModelState.IsValid)
{
tag.Id = Guid.NewGuid();
_context.Add(tag);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(tag);
}
// GET: Tags/Edit/5
public async Task<IActionResult> Edit(Guid? id)
{
if (id == null || _context.Tags == null)
{
return NotFound();
}
var tag = await _context.Tags.FindAsync(id);
if (tag == null)
{
return NotFound();
}
return View(tag);
}
// POST: Tags/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(Guid id, [Bind("Name,Id,CreatedOn,CreatedById,UpdatedOn,UpdatedById")] Tag tag)
{
if (id != tag.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(tag);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TagExists(tag.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(tag);
}
// GET: Tags/Delete/5
public async Task<IActionResult> Delete(Guid? id)
{
if (id == null || _context.Tags == null)
{
return NotFound();
}
var tag = await _context.Tags
.FirstOrDefaultAsync(m => m.Id == id);
if (tag == null)
{
return NotFound();
}
return View(tag);
}
// POST: Tags/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(Guid id)
{
if (_context.Tags == null)
{
return Problem("Entity set 'DatabaseContext.Tags' is null.");
}
var tag = await _context.Tags.FindAsync(id);
if (tag != null)
{
_context.Tags.Remove(tag);
}
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool TagExists(Guid id)
{
return (_context.Tags?.Any(e => e.Id == id)).GetValueOrDefault();
}
}
}

View File

@ -0,0 +1,54 @@
using LANCommander.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace LANCommander.Controllers
{
public class UploadController : Controller
{
private const string UploadDirectory = "Upload";
public JsonResult Init()
{
var key = Guid.NewGuid().ToString();
if (!Directory.Exists(UploadDirectory))
Directory.CreateDirectory(UploadDirectory);
if (!System.IO.File.Exists(Path.Combine(UploadDirectory, key)))
System.IO.File.Create(Path.Combine(UploadDirectory, key)).Close();
return Json(new
{
Key = key
});
}
public async Task<IActionResult> Chunk([FromForm] ChunkUpload chunk)
{
var filePath = Path.Combine(UploadDirectory, chunk.Key.ToString());
if (!System.IO.File.Exists(filePath))
return BadRequest("Destination file not initialized.");
Request.EnableBuffering();
using (var ms = new MemoryStream())
{
await chunk.File.CopyToAsync(ms);
var data = ms.ToArray();
using (var fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None))
{
fs.Position = chunk.Start;
fs.Write(data, 0, data.Length);
}
}
Thread.Sleep(100);
return Json("Done!");
}
}
}

40
Data/DatabaseContext.cs Normal file
View File

@ -0,0 +1,40 @@
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace LANCommander.Data
{
public class DatabaseContext : IdentityDbContext<User>
{
public DatabaseContext(DbContextOptions<DatabaseContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Company>()
.HasMany(c => c.PublishedGames)
.WithOne(g => g.Publisher)
.IsRequired(false);
builder.Entity<Company>()
.HasMany(c => c.DevelopedGames)
.WithOne(g => g.Developer)
.IsRequired(false);
builder.Entity<Game>()
.HasMany(g => g.Archives)
.WithOne(g => g.Game)
.IsRequired(false);
}
public DbSet<Game>? Games { get; set; }
public DbSet<Tag>? Tags { get; set; }
public DbSet<Company>? Companies { get; set; }
}
}

22
Data/Models/Archive.cs Normal file
View File

@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace LANCommander.Data.Models
{
public class Archive : BaseModel
{
public string? Changelog { get; set; }
public string ObjectKey { get; set; }
[Required]
public string Version { get; set; }
public Game Game { get; set; }
public Archive? LastVersion { get; set; }
[NotMapped]
public IFormFile UploadedFile { get; set; }
}
}

15
Data/Models/BaseModel.cs Normal file
View File

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace LANCommander.Data.Models
{
public abstract class BaseModel
{
[Key]
public Guid Id { get; set; }
public DateTime CreatedOn { get; set; }
public Guid CreatedById { get; set; }
public DateTime UpdatedOn { get; set; }
public Guid UpdatedById { get; set; }
}
}

10
Data/Models/Company.cs Normal file
View File

@ -0,0 +1,10 @@
namespace LANCommander.Data.Models
{
public class Company : BaseModel
{
public string Name { get; set; }
public ICollection<Game> PublishedGames { get; set; }
public ICollection<Game> DevelopedGames { get; set; }
}
}

22
Data/Models/Game.cs Normal file
View File

@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace LANCommander.Data.Models
{
[Table("Games")]
public class Game : BaseModel
{
public string Title { get; set; }
public string? SortTitle { get; set; }
public string? DirectoryName { get; set; }
public string Description { get; set; }
public DateTime ReleasedOn { get; set; }
public ICollection<Tag>? Tags { get; set; }
public Company? Publisher { get; set; }
public Company? Developer { get; set; }
public ICollection<Archive>? Archives { get; set; }
}
}

13
Data/Models/Tag.cs Normal file
View File

@ -0,0 +1,13 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace LANCommander.Data.Models
{
[Table("Tags")]
public class Tag : BaseModel
{
public string Name { get; set; }
public List<Game> Games { get; set; }
}
}

11
Data/Models/User.cs Normal file
View File

@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace LANCommander.Data.Models
{
[Table("Users")]
public class User : IdentityUser
{
}
}

95
Data/Repository.cs Normal file
View File

@ -0,0 +1,95 @@
using LANCommander.Data.Models;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
namespace LANCommander.Data
{
public class Repository<T> : IDisposable where T : BaseModel
{
private DbContext Context;
private HttpContext HttpContext;
public Repository(DatabaseContext context, HttpContext httpContext)
{
Context = context;
HttpContext = httpContext;
}
private DbSet<T> DbSet
{
get { return Context.Set<T>(); }
}
private DbSet<User> UserDbSet
{
get { return Context.Set<User>(); }
}
public IQueryable<T> Get(Expression<Func<T, bool>> predicate)
{
return DbSet.AsQueryable().Where(predicate);
}
public async Task<T> Find(Guid id)
{
return await DbSet.FindAsync(id);
}
public T FirstOrDefault(Expression<Func<T, bool>> predicate)
{
return Get(predicate).FirstOrDefault();
}
public async Task<T> Add(T entity)
{
entity.CreatedById = GetCurrentUserId();
entity.UpdatedById = GetCurrentUserId();
entity.CreatedOn = DateTime.Now;
entity.UpdatedOn = DateTime.Now;
await Context.AddAsync(entity);
return entity;
}
public T Update(T entity)
{
entity.UpdatedById = GetCurrentUserId();
entity.UpdatedOn = DateTime.Now;
Context.Update(entity);
return entity;
}
public async Task SaveChanges()
{
await Context.SaveChangesAsync();
}
private User GetUser(string username)
{
return UserDbSet.FirstOrDefault(u => u.UserName == username);
}
private Guid GetCurrentUserId()
{
if (HttpContext != null && HttpContext.User != null && HttpContext.User.Identity != null && HttpContext.User.Identity.IsAuthenticated)
{
var user = GetUser(HttpContext.User.Identity.Name);
if (user == null)
return Guid.Empty;
else
return Guid.Parse(user.Id);
}
else
return Guid.Empty;
}
public void Dispose()
{
}
}
}

52
LANCommander.csproj Normal file
View File

@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<TypeScriptOutDir>wwwroot/js</TypeScriptOutDir>
<TypeScriptOutFile>wwwroot/js/compiled.js</TypeScriptOutFile>
<TypeScriptTarget>ES6</TypeScriptTarget>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<TypeScriptOutDir>wwwroot/js</TypeScriptOutDir>
<TypeScriptOutFile>wwwroot/js/compiled.js</TypeScriptOutFile>
<TypeScriptTarget>ES6</TypeScriptTarget>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-LANCommander-C1F79CFA-9767-4AD7-BD5A-2549F8328A2D</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.9.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.8" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="bin\Debug\net6.0\" />
<Folder Include="Data\Migrations\" />
<Folder Include="Migrations\" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Update="wwwroot\js\Upload.ts">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</TypeScriptCompile>
</ItemGroup>
</Project>

BIN
LANCommander.db Normal file

Binary file not shown.

25
LANCommander.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32328.378
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LANCommander", "LANCommander.csproj", "{C64D17A8-CDB3-4D1E-858F-6CF05B6FED4D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C64D17A8-CDB3-4D1E-858F-6CF05B6FED4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C64D17A8-CDB3-4D1E-858F-6CF05B6FED4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C64D17A8-CDB3-4D1E-858F-6CF05B6FED4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C64D17A8-CDB3-4D1E-858F-6CF05B6FED4D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CBA5868D-8784-40B3-8E3D-46C24FDDC425}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,332 @@
// <auto-generated />
using System;
using LANCommander.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace LANCommander.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20220905222402_InitialSeed")]
partial class InitialSeed
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.8");
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<DateTime>("ReleasedOn")
.HasColumnType("TEXT");
b.Property<string>("SortTitle")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Games");
});
modelBuilder.Entity("LANCommander.Data.Models.Tag", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Tags");
});
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,259 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LANCommander.Migrations
{
public partial class InitialSeed : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
UserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
PasswordHash = table.Column<string>(type: "TEXT", nullable: true),
SecurityStamp = table.Column<string>(type: "TEXT", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true),
PhoneNumber = table.Column<string>(type: "TEXT", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "TEXT", nullable: true),
LockoutEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
AccessFailedCount = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Games",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Title = table.Column<string>(type: "TEXT", nullable: false),
SortTitle = table.Column<string>(type: "TEXT", nullable: false),
ReleasedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
CreatedById = table.Column<Guid>(type: "TEXT", nullable: false),
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Games", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Tags",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: false),
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
CreatedById = table.Column<Guid>(type: "TEXT", nullable: false),
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tags", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
RoleId = table.Column<string>(type: "TEXT", nullable: false),
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
UserId = table.Column<string>(type: "TEXT", nullable: false),
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
ProviderKey = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
ProviderDisplayName = table.Column<string>(type: "TEXT", nullable: true),
UserId = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(type: "TEXT", nullable: false),
RoleId = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "TEXT", nullable: false),
LoginProvider = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
Name = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
Value = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "Games");
migrationBuilder.DropTable(
name: "Tags");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View File

@ -0,0 +1,429 @@
// <auto-generated />
using System;
using LANCommander.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace LANCommander.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20220907043213_AddCompanies")]
partial class AddCompanies
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.8");
modelBuilder.Entity("GameTag", b =>
{
b.Property<Guid>("GamesId")
.HasColumnType("TEXT");
b.Property<Guid>("TagsId")
.HasColumnType("TEXT");
b.HasKey("GamesId", "TagsId");
b.HasIndex("TagsId");
b.ToTable("GameTag");
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Companies");
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("DeveloperId")
.HasColumnType("TEXT");
b.Property<Guid>("PublisherId")
.HasColumnType("TEXT");
b.Property<DateTime>("ReleasedOn")
.HasColumnType("TEXT");
b.Property<string>("SortTitle")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DeveloperId");
b.HasIndex("PublisherId");
b.ToTable("Games");
});
modelBuilder.Entity("LANCommander.Data.Models.Tag", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Tags");
});
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("GameTag", b =>
{
b.HasOne("LANCommander.Data.Models.Game", null)
.WithMany()
.HasForeignKey("GamesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.Tag", null)
.WithMany()
.HasForeignKey("TagsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.HasOne("LANCommander.Data.Models.Company", "Developer")
.WithMany("DevelopedGames")
.HasForeignKey("DeveloperId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.Company", "Publisher")
.WithMany("PublishedGames")
.HasForeignKey("PublisherId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Developer");
b.Navigation("Publisher");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Navigation("DevelopedGames");
b.Navigation("PublishedGames");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,142 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LANCommander.Migrations
{
public partial class AddCompanies : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Description",
table: "Games",
type: "TEXT",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<Guid>(
name: "DeveloperId",
table: "Games",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddColumn<Guid>(
name: "PublisherId",
table: "Games",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateTable(
name: "Companies",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: false),
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
CreatedById = table.Column<Guid>(type: "TEXT", nullable: false),
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Companies", x => x.Id);
});
migrationBuilder.CreateTable(
name: "GameTag",
columns: table => new
{
GamesId = table.Column<Guid>(type: "TEXT", nullable: false),
TagsId = table.Column<Guid>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_GameTag", x => new { x.GamesId, x.TagsId });
table.ForeignKey(
name: "FK_GameTag_Games_GamesId",
column: x => x.GamesId,
principalTable: "Games",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_GameTag_Tags_TagsId",
column: x => x.TagsId,
principalTable: "Tags",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Games_DeveloperId",
table: "Games",
column: "DeveloperId");
migrationBuilder.CreateIndex(
name: "IX_Games_PublisherId",
table: "Games",
column: "PublisherId");
migrationBuilder.CreateIndex(
name: "IX_GameTag_TagsId",
table: "GameTag",
column: "TagsId");
migrationBuilder.AddForeignKey(
name: "FK_Games_Companies_DeveloperId",
table: "Games",
column: "DeveloperId",
principalTable: "Companies",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Games_Companies_PublisherId",
table: "Games",
column: "PublisherId",
principalTable: "Companies",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Games_Companies_DeveloperId",
table: "Games");
migrationBuilder.DropForeignKey(
name: "FK_Games_Companies_PublisherId",
table: "Games");
migrationBuilder.DropTable(
name: "Companies");
migrationBuilder.DropTable(
name: "GameTag");
migrationBuilder.DropIndex(
name: "IX_Games_DeveloperId",
table: "Games");
migrationBuilder.DropIndex(
name: "IX_Games_PublisherId",
table: "Games");
migrationBuilder.DropColumn(
name: "Description",
table: "Games");
migrationBuilder.DropColumn(
name: "DeveloperId",
table: "Games");
migrationBuilder.DropColumn(
name: "PublisherId",
table: "Games");
}
}
}

View File

@ -0,0 +1,424 @@
// <auto-generated />
using System;
using LANCommander.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace LANCommander.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20221229082813_AlterGameRequiredFields")]
partial class AlterGameRequiredFields
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.8");
modelBuilder.Entity("GameTag", b =>
{
b.Property<Guid>("GamesId")
.HasColumnType("TEXT");
b.Property<Guid>("TagsId")
.HasColumnType("TEXT");
b.HasKey("GamesId", "TagsId");
b.HasIndex("TagsId");
b.ToTable("GameTag");
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Companies");
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid?>("DeveloperId")
.HasColumnType("TEXT");
b.Property<Guid?>("PublisherId")
.HasColumnType("TEXT");
b.Property<DateTime>("ReleasedOn")
.HasColumnType("TEXT");
b.Property<string>("SortTitle")
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DeveloperId");
b.HasIndex("PublisherId");
b.ToTable("Games");
});
modelBuilder.Entity("LANCommander.Data.Models.Tag", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Tags");
});
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("GameTag", b =>
{
b.HasOne("LANCommander.Data.Models.Game", null)
.WithMany()
.HasForeignKey("GamesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.Tag", null)
.WithMany()
.HasForeignKey("TagsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.HasOne("LANCommander.Data.Models.Company", "Developer")
.WithMany("DevelopedGames")
.HasForeignKey("DeveloperId");
b.HasOne("LANCommander.Data.Models.Company", "Publisher")
.WithMany("PublishedGames")
.HasForeignKey("PublisherId");
b.Navigation("Developer");
b.Navigation("Publisher");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Navigation("DevelopedGames");
b.Navigation("PublishedGames");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,116 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LANCommander.Migrations
{
public partial class AlterGameRequiredFields : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Games_Companies_DeveloperId",
table: "Games");
migrationBuilder.DropForeignKey(
name: "FK_Games_Companies_PublisherId",
table: "Games");
migrationBuilder.AlterColumn<string>(
name: "SortTitle",
table: "Games",
type: "TEXT",
nullable: true,
oldClrType: typeof(string),
oldType: "TEXT");
migrationBuilder.AlterColumn<Guid>(
name: "PublisherId",
table: "Games",
type: "TEXT",
nullable: true,
oldClrType: typeof(Guid),
oldType: "TEXT");
migrationBuilder.AlterColumn<Guid>(
name: "DeveloperId",
table: "Games",
type: "TEXT",
nullable: true,
oldClrType: typeof(Guid),
oldType: "TEXT");
migrationBuilder.AddForeignKey(
name: "FK_Games_Companies_DeveloperId",
table: "Games",
column: "DeveloperId",
principalTable: "Companies",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Games_Companies_PublisherId",
table: "Games",
column: "PublisherId",
principalTable: "Companies",
principalColumn: "Id");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Games_Companies_DeveloperId",
table: "Games");
migrationBuilder.DropForeignKey(
name: "FK_Games_Companies_PublisherId",
table: "Games");
migrationBuilder.AlterColumn<string>(
name: "SortTitle",
table: "Games",
type: "TEXT",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "PublisherId",
table: "Games",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "DeveloperId",
table: "Games",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "TEXT",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Games_Companies_DeveloperId",
table: "Games",
column: "DeveloperId",
principalTable: "Companies",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Games_Companies_PublisherId",
table: "Games",
column: "PublisherId",
principalTable: "Companies",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@ -0,0 +1,491 @@
// <auto-generated />
using System;
using LANCommander.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace LANCommander.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20221230033714_AddGameArchives")]
partial class AddGameArchives
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.8");
modelBuilder.Entity("GameTag", b =>
{
b.Property<Guid>("GamesId")
.HasColumnType("TEXT");
b.Property<Guid>("TagsId")
.HasColumnType("TEXT");
b.HasKey("GamesId", "TagsId");
b.HasIndex("TagsId");
b.ToTable("GameTag");
});
modelBuilder.Entity("LANCommander.Data.Models.Archive", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("Changelog")
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<Guid>("GameId")
.HasColumnType("TEXT");
b.Property<Guid?>("LastVersionId")
.HasColumnType("TEXT");
b.Property<string>("ObjectKey")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.Property<string>("Version")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("GameId");
b.HasIndex("LastVersionId");
b.ToTable("Archive");
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Companies");
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid?>("DeveloperId")
.HasColumnType("TEXT");
b.Property<string>("DirectoryName")
.HasColumnType("TEXT");
b.Property<Guid?>("PublisherId")
.HasColumnType("TEXT");
b.Property<DateTime>("ReleasedOn")
.HasColumnType("TEXT");
b.Property<string>("SortTitle")
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DeveloperId");
b.HasIndex("PublisherId");
b.ToTable("Games");
});
modelBuilder.Entity("LANCommander.Data.Models.Tag", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Tags");
});
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("GameTag", b =>
{
b.HasOne("LANCommander.Data.Models.Game", null)
.WithMany()
.HasForeignKey("GamesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.Tag", null)
.WithMany()
.HasForeignKey("TagsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Archive", b =>
{
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Archives")
.HasForeignKey("GameId");
b.HasOne("LANCommander.Data.Models.Archive", "LastVersion")
.WithMany()
.HasForeignKey("LastVersionId");
b.Navigation("Game");
b.Navigation("LastVersion");
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.HasOne("LANCommander.Data.Models.Company", "Developer")
.WithMany("DevelopedGames")
.HasForeignKey("DeveloperId");
b.HasOne("LANCommander.Data.Models.Company", "Publisher")
.WithMany("PublishedGames")
.HasForeignKey("PublisherId");
b.Navigation("Developer");
b.Navigation("Publisher");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Navigation("DevelopedGames");
b.Navigation("PublishedGames");
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.Navigation("Archives");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LANCommander.Migrations
{
public partial class AddGameArchives : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "DirectoryName",
table: "Games",
type: "TEXT",
nullable: true);
migrationBuilder.CreateTable(
name: "Archive",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Changelog = table.Column<string>(type: "TEXT", nullable: true),
ObjectKey = table.Column<string>(type: "TEXT", nullable: false),
Version = table.Column<string>(type: "TEXT", nullable: false),
GameId = table.Column<Guid>(type: "TEXT", nullable: false),
LastVersionId = table.Column<Guid>(type: "TEXT", nullable: true),
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
CreatedById = table.Column<Guid>(type: "TEXT", nullable: false),
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Archive", x => x.Id);
table.ForeignKey(
name: "FK_Archive_Archive_LastVersionId",
column: x => x.LastVersionId,
principalTable: "Archive",
principalColumn: "Id");
table.ForeignKey(
name: "FK_Archive_Games_GameId",
column: x => x.GameId,
principalTable: "Games",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_Archive_GameId",
table: "Archive",
column: "GameId");
migrationBuilder.CreateIndex(
name: "IX_Archive_LastVersionId",
table: "Archive",
column: "LastVersionId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Archive");
migrationBuilder.DropColumn(
name: "DirectoryName",
table: "Games");
}
}
}

View File

@ -0,0 +1,489 @@
// <auto-generated />
using System;
using LANCommander.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace LANCommander.Migrations
{
[DbContext(typeof(DatabaseContext))]
partial class DatabaseContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.8");
modelBuilder.Entity("GameTag", b =>
{
b.Property<Guid>("GamesId")
.HasColumnType("TEXT");
b.Property<Guid>("TagsId")
.HasColumnType("TEXT");
b.HasKey("GamesId", "TagsId");
b.HasIndex("TagsId");
b.ToTable("GameTag", (string)null);
});
modelBuilder.Entity("LANCommander.Data.Models.Archive", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("Changelog")
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<Guid>("GameId")
.HasColumnType("TEXT");
b.Property<Guid?>("LastVersionId")
.HasColumnType("TEXT");
b.Property<string>("ObjectKey")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.Property<string>("Version")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("GameId");
b.HasIndex("LastVersionId");
b.ToTable("Archive", (string)null);
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Companies", (string)null);
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid?>("DeveloperId")
.HasColumnType("TEXT");
b.Property<string>("DirectoryName")
.HasColumnType("TEXT");
b.Property<Guid?>("PublisherId")
.HasColumnType("TEXT");
b.Property<DateTime>("ReleasedOn")
.HasColumnType("TEXT");
b.Property<string>("SortTitle")
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DeveloperId");
b.HasIndex("PublisherId");
b.ToTable("Games", (string)null);
});
modelBuilder.Entity("LANCommander.Data.Models.Tag", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Tags", (string)null);
});
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("GameTag", b =>
{
b.HasOne("LANCommander.Data.Models.Game", null)
.WithMany()
.HasForeignKey("GamesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.Tag", null)
.WithMany()
.HasForeignKey("TagsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Archive", b =>
{
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Archives")
.HasForeignKey("GameId");
b.HasOne("LANCommander.Data.Models.Archive", "LastVersion")
.WithMany()
.HasForeignKey("LastVersionId");
b.Navigation("Game");
b.Navigation("LastVersion");
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.HasOne("LANCommander.Data.Models.Company", "Developer")
.WithMany("DevelopedGames")
.HasForeignKey("DeveloperId");
b.HasOne("LANCommander.Data.Models.Company", "Publisher")
.WithMany("PublishedGames")
.HasForeignKey("PublisherId");
b.Navigation("Developer");
b.Navigation("Publisher");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("LANCommander.Data.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Navigation("DevelopedGames");
b.Navigation("PublishedGames");
});
modelBuilder.Entity("LANCommander.Data.Models.Game", b =>
{
b.Navigation("Archives");
});
#pragma warning restore 612, 618
}
}
}

11
Models/ChunkUpload.cs Normal file
View File

@ -0,0 +1,11 @@
namespace LANCommander.Models
{
public class ChunkUpload
{
public long Start { get; set; }
public long End { get; set; }
public long Total { get; set; }
public Guid Key { get; set; }
public IFormFile File { get; set; }
}
}

9
Models/ErrorViewModel.cs Normal file
View File

@ -0,0 +1,9 @@
namespace LANCommander.Models
{
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

52
Program.cs Normal file
View File

@ -0,0 +1,52 @@
using LANCommander.Data;
using LANCommander.Data.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<global::LANCommander.Data.DatabaseContext>((global::Microsoft.EntityFrameworkCore.DbContextOptionsBuilder options) =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<User>((IdentityOptions options) => {
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireNonAlphanumeric = false;
options.SignIn.RequireConfirmedEmail = false;
}).AddEntityFrameworkStores<DatabaseContext>();
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();

View File

@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:19829",
"sslPort": 44328
}
},
"profiles": {
"LANCommander": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7087;http://localhost:5087",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,8 @@
{
"dependencies": {
"mssql1": {
"type": "mssql",
"connectionId": "ConnectionStrings:DefaultConnection"
}
}
}

View File

@ -0,0 +1,8 @@
{
"dependencies": {
"mssql1": {
"type": "mssql.local",
"connectionId": "ConnectionStrings:DefaultConnection"
}
}
}

3
ScaffoldingReadMe.txt Normal file
View File

@ -0,0 +1,3 @@
Support for ASP.NET Core Identity was added to your project.
For setup and configuration information, see https://go.microsoft.com/fwlink/?linkid=2116645.

View File

@ -0,0 +1,53 @@
@model LANCommander.Data.Models.Company
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Company</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedOn" class="control-label"></label>
<input asp-for="CreatedOn" class="form-control" />
<span asp-validation-for="CreatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedById" class="control-label"></label>
<input asp-for="CreatedById" class="form-control" />
<span asp-validation-for="CreatedById" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedOn" class="control-label"></label>
<input asp-for="UpdatedOn" class="form-control" />
<span asp-validation-for="UpdatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedById" class="control-label"></label>
<input asp-for="UpdatedById" class="form-control" />
<span asp-validation-for="UpdatedById" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,51 @@
@model LANCommander.Data.Models.Company
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Company</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Name)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedById)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedById)
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>

View File

@ -0,0 +1,48 @@
@model LANCommander.Data.Models.Company
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>Company</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Name)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedById)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedById)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model?.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>

View File

@ -0,0 +1,54 @@
@model LANCommander.Data.Models.Company
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Company</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="CreatedOn" class="control-label"></label>
<input asp-for="CreatedOn" class="form-control" />
<span asp-validation-for="CreatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedById" class="control-label"></label>
<input asp-for="CreatedById" class="form-control" />
<span asp-validation-for="CreatedById" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedOn" class="control-label"></label>
<input asp-for="UpdatedOn" class="form-control" />
<span asp-validation-for="UpdatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedById" class="control-label"></label>
<input asp-for="UpdatedById" class="form-control" />
<span asp-validation-for="UpdatedById" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,59 @@
@model IEnumerable<LANCommander.Data.Models.Company>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.CreatedOn)
</th>
<th>
@Html.DisplayNameFor(model => model.CreatedById)
</th>
<th>
@Html.DisplayNameFor(model => model.UpdatedOn)
</th>
<th>
@Html.DisplayNameFor(model => model.UpdatedById)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.CreatedOn)
</td>
<td>
@Html.DisplayFor(modelItem => item.CreatedById)
</td>
<td>
@Html.DisplayFor(modelItem => item.UpdatedOn)
</td>
<td>
@Html.DisplayFor(modelItem => item.UpdatedById)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>

View File

@ -0,0 +1,54 @@
@model LANCommander.Data.Models.Archive
@{
ViewData["Title"] = "Add Archive";
}
<h1>Add Archive</h1>
<h4>@Html.DisplayFor(m => m.Game.Title)</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="AddArchive" enctype="multipart/form-data" >
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Version" class="control-label"></label>
<input asp-for="Version" class="form-control" />
<span asp-validation-for="Version" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Changelog" class="control-label"></label>
<textarea asp-for="Changelog" class="form-control"></textarea>
<span asp-validation-for="Changelog" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UploadedFile" class="control-label"></label>
<input type="file" asp-for="UploadedFile" class="form-control" />
<span asp-validation-for="UploadedFile" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label">Last Version</label>
<input class="form-control" value="@Html.DisplayFor(m => m.LastVersion.Version)" />
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="~/js/Upload.js"></script>
<script>
var uploader = new Uploader();
uploader.Init('UploadedFile');
</script>
}

48
Views/Games/Create.cshtml Normal file
View File

@ -0,0 +1,48 @@
@model LANCommander.Data.Models.Game
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Game</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SortTitle" class="control-label"></label>
<input asp-for="SortTitle" class="form-control" />
<span asp-validation-for="SortTitle" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleasedOn" class="control-label"></label>
<input asp-for="ReleasedOn" class="form-control" />
<span asp-validation-for="ReleasedOn" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

69
Views/Games/Delete.cshtml Normal file
View File

@ -0,0 +1,69 @@
@model LANCommander.Data.Models.Game
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Game</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Title)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.SortTitle)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.SortTitle)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Description)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Description)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ReleasedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ReleasedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedById)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedById)
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>

View File

@ -0,0 +1,66 @@
@model LANCommander.Data.Models.Game
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>Game</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Title)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.SortTitle)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.SortTitle)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Description)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Description)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ReleasedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ReleasedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedById)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedById)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model?.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>

69
Views/Games/Edit.cshtml Normal file
View File

@ -0,0 +1,69 @@
@model LANCommander.Data.Models.Game
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Game</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SortTitle" class="control-label"></label>
<input asp-for="SortTitle" class="form-control" />
<span asp-validation-for="SortTitle" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleasedOn" class="control-label"></label>
<input asp-for="ReleasedOn" class="form-control" />
<span asp-validation-for="ReleasedOn" class="text-danger"></span>
</div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="CreatedOn" class="control-label"></label>
<input asp-for="CreatedOn" class="form-control" />
<span asp-validation-for="CreatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedById" class="control-label"></label>
<input asp-for="CreatedById" class="form-control" />
<span asp-validation-for="CreatedById" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedOn" class="control-label"></label>
<input asp-for="UpdatedOn" class="form-control" />
<span asp-validation-for="UpdatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedById" class="control-label"></label>
<input asp-for="UpdatedById" class="form-control" />
<span asp-validation-for="UpdatedById" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

77
Views/Games/Index.cshtml Normal file
View File

@ -0,0 +1,77 @@
@model IEnumerable<LANCommander.Data.Models.Game>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.SortTitle)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleasedOn)
</th>
<th>
@Html.DisplayNameFor(model => model.CreatedOn)
</th>
<th>
@Html.DisplayNameFor(model => model.CreatedById)
</th>
<th>
@Html.DisplayNameFor(model => model.UpdatedOn)
</th>
<th>
@Html.DisplayNameFor(model => model.UpdatedById)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.SortTitle)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleasedOn)
</td>
<td>
@Html.DisplayFor(modelItem => item.CreatedOn)
</td>
<td>
@Html.DisplayFor(modelItem => item.CreatedById)
</td>
<td>
@Html.DisplayFor(modelItem => item.UpdatedOn)
</td>
<td>
@Html.DisplayFor(modelItem => item.UpdatedById)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>

8
Views/Home/Index.cshtml Normal file
View File

@ -0,0 +1,8 @@
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

View File

@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

25
Views/Shared/Error.cshtml Normal file
View File

@ -0,0 +1,25 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - LANCommander</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/LANCommander.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">LANCommander</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
<partial name="_LoginPartial" />
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2022 - LANCommander - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>

View File

@ -0,0 +1,48 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
a {
color: #0077cc;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}

View File

@ -0,0 +1,27 @@
@using LANCommander.Data.Models
@using Microsoft.AspNetCore.Identity
@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @User.Identity?.Name!</a>
</li>
<li class="nav-item">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })">
<button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>

View File

@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

53
Views/Tags/Create.cshtml Normal file
View File

@ -0,0 +1,53 @@
@model LANCommander.Data.Models.Tag
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Tag</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedOn" class="control-label"></label>
<input asp-for="CreatedOn" class="form-control" />
<span asp-validation-for="CreatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedById" class="control-label"></label>
<input asp-for="CreatedById" class="form-control" />
<span asp-validation-for="CreatedById" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedOn" class="control-label"></label>
<input asp-for="UpdatedOn" class="form-control" />
<span asp-validation-for="UpdatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedById" class="control-label"></label>
<input asp-for="UpdatedById" class="form-control" />
<span asp-validation-for="UpdatedById" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

51
Views/Tags/Delete.cshtml Normal file
View File

@ -0,0 +1,51 @@
@model LANCommander.Data.Models.Tag
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Tag</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Name)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedById)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedById)
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>

48
Views/Tags/Details.cshtml Normal file
View File

@ -0,0 +1,48 @@
@model LANCommander.Data.Models.Tag
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>Tag</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Name)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.CreatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.CreatedById)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedOn)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedOn)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.UpdatedById)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.UpdatedById)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model?.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>

54
Views/Tags/Edit.cshtml Normal file
View File

@ -0,0 +1,54 @@
@model LANCommander.Data.Models.Tag
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Tag</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="CreatedOn" class="control-label"></label>
<input asp-for="CreatedOn" class="form-control" />
<span asp-validation-for="CreatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedById" class="control-label"></label>
<input asp-for="CreatedById" class="form-control" />
<span asp-validation-for="CreatedById" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedOn" class="control-label"></label>
<input asp-for="UpdatedOn" class="form-control" />
<span asp-validation-for="UpdatedOn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UpdatedById" class="control-label"></label>
<input asp-for="UpdatedById" class="form-control" />
<span asp-validation-for="UpdatedById" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

59
Views/Tags/Index.cshtml Normal file
View File

@ -0,0 +1,59 @@
@model IEnumerable<LANCommander.Data.Models.Tag>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.CreatedOn)
</th>
<th>
@Html.DisplayNameFor(model => model.CreatedById)
</th>
<th>
@Html.DisplayNameFor(model => model.UpdatedOn)
</th>
<th>
@Html.DisplayNameFor(model => model.UpdatedById)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.CreatedOn)
</td>
<td>
@Html.DisplayFor(modelItem => item.CreatedById)
</td>
<td>
@Html.DisplayFor(modelItem => item.UpdatedOn)
</td>
<td>
@Html.DisplayFor(modelItem => item.UpdatedById)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>

View File

@ -0,0 +1,3 @@
@using LANCommander
@using LANCommander.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

3
Views/_ViewStart.cshtml Normal file
View File

@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

12
appsettings.json Normal file
View File

@ -0,0 +1,12 @@
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=LANCommander.db;Cache=Shared"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

13
tsconfig.json Normal file
View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es6"
},
"exclude": [
"node_modules",
"wwwroot/lib"
]
}

18
wwwroot/css/site.css Normal file
View File

@ -0,0 +1,18 @@
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
}

BIN
wwwroot/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

82
wwwroot/js/Upload.js Normal file
View File

@ -0,0 +1,82 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
class Chunk {
constructor(start, end, index) {
this.Start = start;
this.End = end;
this.Index = index;
}
}
class Uploader {
constructor() {
this.InitRoute = "/Upload/Init";
this.ChunkRoute = "/Upload/Chunk";
this.MaxChunkSize = 1024 * 1024 * 25;
}
Init(elementId) {
this.FileInput = document.getElementById(elementId);
this.ParentForm = this.FileInput.closest("form");
this.Chunks = [];
this.ParentForm.onsubmit = (e) => __awaiter(this, void 0, void 0, function* () {
yield this.HandleFormSubmit(e);
});
}
HandleFormSubmit(e) {
return __awaiter(this, void 0, void 0, function* () {
e.preventDefault();
this.File = this.FileInput.files.item(0);
this.TotalChunks = Math.ceil(this.File.size / this.MaxChunkSize);
var response = yield fetch(this.InitRoute, {
method: "POST"
});
const data = yield response.json();
if (response.ok) {
this.Key = data.key;
this.GetChunks();
for (let chunk of this.Chunks) {
let dataChunk = yield this.ReadChunkFromFile(this.File, chunk);
let formData = new FormData();
formData.append('file', this.File.slice(chunk.Start, chunk.End));
formData.append('start', chunk.Start.toString());
formData.append('end', chunk.End.toString());
formData.append('key', this.Key);
formData.append('total', this.File.size.toString());
console.info(`Uploading chunk ${chunk.Index}/${this.TotalChunks}...`);
let response = yield fetch(this.ChunkRoute, {
method: "POST",
body: formData
});
debugger;
}
}
});
}
ReadChunkFromFile(file, chunk) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
let blob = this.File.slice(chunk.Start, chunk.End);
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(blob);
});
}
GetChunks() {
for (let currentChunk = 1; currentChunk <= this.TotalChunks; currentChunk++) {
let start = (currentChunk - 1) * this.MaxChunkSize;
let end = (currentChunk * this.MaxChunkSize) - 1;
if (currentChunk == this.TotalChunks)
end = this.File.size;
this.Chunks.push(new Chunk(start, end, currentChunk));
}
}
}
//# sourceMappingURL=Upload.js.map

1
wwwroot/js/Upload.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"Upload.js","sourceRoot":"","sources":["Upload.ts"],"names":[],"mappings":";;;;;;;;;AAAA,MAAM,KAAK;IAKP,YAAY,KAAa,EAAE,GAAW,EAAE,KAAa;QACjD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;CACJ;AAED,MAAM,QAAQ;IAAd;QAKI,cAAS,GAAW,cAAc,CAAC;QACnC,eAAU,GAAW,eAAe,CAAC;QAErC,iBAAY,GAAW,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;IAoF5C,CAAC;IA7EG,IAAI,CAAC,SAAiB;QAClB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAqB,CAAC;QACxE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QAEjB,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAO,CAAC,EAAE,EAAE;YACnC,MAAM,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAA,CAAC;IACN,CAAC;IAEK,gBAAgB,CAAC,CAAc;;YACjC,CAAC,CAAC,cAAc,EAAE,CAAC;YAEnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACzC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;YAEjE,IAAI,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE;gBACvC,MAAM,EAAE,MAAM;aACjB,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAEnC,IAAI,QAAQ,CAAC,EAAE,EAAE;gBACb,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;gBAEpB,IAAI,CAAC,SAAS,EAAE,CAAC;gBAEjB,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE;oBAC3B,IAAI,SAAS,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;oBAE/D,IAAI,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;oBAE9B,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;oBACjE,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;oBACjD,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;oBAC7C,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;oBACjC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;oBAEpD,OAAO,CAAC,IAAI,CAAC,mBAAmB,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,WAAW,KAAK,CAAC,CAAC;oBAEtE,IAAI,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE;wBACxC,MAAM,EAAE,MAAM;wBACd,IAAI,EAAE,QAAQ;qBACjB,CAAC,CAAC;oBAEH,QAAQ,CAAC;iBACZ;aACJ;QACL,CAAC;KAAA;IAED,iBAAiB,CAAC,IAAU,EAAE,KAAY;QACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;YAEnD,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;gBACjB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3B,CAAC,CAAA;YAED,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC;YAExB,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,SAAS;QACL,KAAK,IAAI,YAAY,GAAG,CAAC,EAAE,YAAY,IAAI,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,EAAE;YACzE,IAAI,KAAK,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;YACnD,IAAI,GAAG,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;YAEjD,IAAI,YAAY,IAAI,IAAI,CAAC,WAAW;gBAChC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAEzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;SACzD;IACL,CAAC;CACJ"}

105
wwwroot/js/Upload.ts Normal file
View File

@ -0,0 +1,105 @@
class Chunk {
Index: number;
Start: number;
End: number;
constructor(start: number, end: number, index: number) {
this.Start = start;
this.End = end;
this.Index = index;
}
}
class Uploader {
ParentForm: HTMLFormElement;
FileInput: HTMLInputElement;
File: File;
InitRoute: string = "/Upload/Init";
ChunkRoute: string = "/Upload/Chunk";
MaxChunkSize: number = 1024 * 1024 * 25;
TotalChunks: number;
CurrentChunk: number;
Chunks: Chunk[];
Key: string;
Init(elementId: string) {
this.FileInput = document.getElementById(elementId) as HTMLInputElement;
this.ParentForm = this.FileInput.closest("form");
this.Chunks = [];
this.ParentForm.onsubmit = async (e) => {
await this.HandleFormSubmit(e);
};
}
async HandleFormSubmit(e: SubmitEvent) {
e.preventDefault();
this.File = this.FileInput.files.item(0);
this.TotalChunks = Math.ceil(this.File.size / this.MaxChunkSize);
var response = await fetch(this.InitRoute, {
method: "POST"
});
const data = await response.json();
if (response.ok) {
this.Key = data.key;
this.GetChunks();
for (let chunk of this.Chunks) {
let dataChunk = await this.ReadChunkFromFile(this.File, chunk);
let formData = new FormData();
formData.append('file', this.File.slice(chunk.Start, chunk.End));
formData.append('start', chunk.Start.toString());
formData.append('end', chunk.End.toString());
formData.append('key', this.Key);
formData.append('total', this.File.size.toString());
console.info(`Uploading chunk ${chunk.Index}/${this.TotalChunks}...`);
let response = await fetch(this.ChunkRoute, {
method: "POST",
body: formData
});
debugger;
}
}
}
ReadChunkFromFile(file: File, chunk: Chunk): Promise<string | ArrayBuffer> {
return new Promise((resolve, reject) => {
let reader = new FileReader();
let blob = this.File.slice(chunk.Start, chunk.End);
reader.onload = () => {
resolve(reader.result);
}
reader.onerror = reject;
reader.readAsArrayBuffer(blob);
});
}
GetChunks() {
for (let currentChunk = 1; currentChunk <= this.TotalChunks; currentChunk++) {
let start = (currentChunk - 1) * this.MaxChunkSize;
let end = (currentChunk * this.MaxChunkSize) - 1;
if (currentChunk == this.TotalChunks)
end = this.File.size;
this.Chunks.push(new Chunk(start, end, currentChunk));
}
}
}

4
wwwroot/js/site.js Normal file
View File

@ -0,0 +1,4 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More