Compare commits
	
		
			No commits in common. "feat/add-auth" and "main" have entirely different histories.
		
	
	
		
			feat/add-a
			...
			main
		
	
		
					 78 changed files with 12 additions and 4829 deletions
				
			
		|  | @ -1,10 +0,0 @@ | ||||||
| @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> |  | ||||||
|  | @ -1,23 +0,0 @@ | ||||||
| // 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 turf_tasker.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() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,8 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ConfirmEmailModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Confirm email"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h1>@ViewData["Title"]</h1> |  | ||||||
| <partial name="_StatusMessage" model="Model.StatusMessage" /> |  | ||||||
|  | @ -1,51 +0,0 @@ | ||||||
| // 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.Linq; |  | ||||||
| using System.Text; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.AspNetCore.WebUtilities; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class ConfirmEmailModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
| 
 |  | ||||||
|         public ConfirmEmailModel(UserManager<IdentityUser> 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> |  | ||||||
|         [TempData] |  | ||||||
|         public string StatusMessage { get; set; } |  | ||||||
|         public async Task<IActionResult> OnGetAsync(string userId, string code) |  | ||||||
|         { |  | ||||||
|             if (userId == null || code == null) |  | ||||||
|             { |  | ||||||
|                 return RedirectToPage("/Index"); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var user = await _userManager.FindByIdAsync(userId); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{userId}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); |  | ||||||
|             var result = await _userManager.ConfirmEmailAsync(user, code); |  | ||||||
|             StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,8 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ConfirmEmailChangeModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Confirm email change"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h1>@ViewData["Title"]</h1> |  | ||||||
| <partial name="_StatusMessage" model="Model.StatusMessage" /> |  | ||||||
|  | @ -1,69 +0,0 @@ | ||||||
| // 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.Text; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.AspNetCore.WebUtilities; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class ConfirmEmailChangeModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
| 
 |  | ||||||
|         public ConfirmEmailChangeModel(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> 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> |  | ||||||
|         [TempData] |  | ||||||
|         public string StatusMessage { get; set; } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGetAsync(string userId, string email, string code) |  | ||||||
|         { |  | ||||||
|             if (userId == null || email == null || code == null) |  | ||||||
|             { |  | ||||||
|                 return RedirectToPage("/Index"); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var user = await _userManager.FindByIdAsync(userId); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{userId}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); |  | ||||||
|             var result = await _userManager.ChangeEmailAsync(user, email, code); |  | ||||||
|             if (!result.Succeeded) |  | ||||||
|             { |  | ||||||
|                 StatusMessage = "Error changing email."; |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // In our UI email and user name are one and the same, so when we update the email |  | ||||||
|             // we need to update the user name. |  | ||||||
|             var setUserNameResult = await _userManager.SetUserNameAsync(user, email); |  | ||||||
|             if (!setUserNameResult.Succeeded) |  | ||||||
|             { |  | ||||||
|                 StatusMessage = "Error changing user name."; |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             await _signInManager.RefreshSignInAsync(user); |  | ||||||
|             StatusMessage = "Thank you for confirming your email change."; |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,33 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ExternalLoginModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Register"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h1>@ViewData["Title"]</h1> |  | ||||||
| <h2 id="external-login-title">Associate your @Model.ProviderDisplayName account.</h2> |  | ||||||
| <hr /> |  | ||||||
| 
 |  | ||||||
| <p id="external-login-description" class="text-info"> |  | ||||||
|     You've successfully authenticated with <strong>@Model.ProviderDisplayName</strong>. |  | ||||||
|     Please enter an email address for this site below and click the Register button to finish |  | ||||||
|     logging in. |  | ||||||
| </p> |  | ||||||
| 
 |  | ||||||
| <div class="row"> |  | ||||||
|     <div class="col-md-4"> |  | ||||||
|         <form asp-page-handler="Confirmation" asp-route-returnUrl="@Model.ReturnUrl" method="post"> |  | ||||||
|             <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Email" class="form-control" autocomplete="email" placeholder="Please enter your email."/> |  | ||||||
|                 <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">Register</button> |  | ||||||
|         </form> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,223 +0,0 @@ | ||||||
| // 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.Security.Claims; |  | ||||||
| using System.Text; |  | ||||||
| using System.Text.Encodings.Web; |  | ||||||
| using System.Threading; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.Extensions.Options; |  | ||||||
| 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 turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     [AllowAnonymous] |  | ||||||
|     public class ExternalLoginModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly IUserStore<IdentityUser> _userStore; |  | ||||||
|         private readonly IUserEmailStore<IdentityUser> _emailStore; |  | ||||||
|         private readonly IEmailSender _emailSender; |  | ||||||
|         private readonly ILogger<ExternalLoginModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public ExternalLoginModel( |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             IUserStore<IdentityUser> userStore, |  | ||||||
|             ILogger<ExternalLoginModel> logger, |  | ||||||
|             IEmailSender emailSender) |  | ||||||
|         { |  | ||||||
|             _signInManager = signInManager; |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _userStore = userStore; |  | ||||||
|             _emailStore = GetEmailStore(); |  | ||||||
|             _logger = logger; |  | ||||||
|             _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 string ProviderDisplayName { 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; } |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         public IActionResult OnGet() => RedirectToPage("./Login"); |  | ||||||
| 
 |  | ||||||
|         public IActionResult OnPost(string provider, string returnUrl = null) |  | ||||||
|         { |  | ||||||
|             // Request a redirect to the external login provider. |  | ||||||
|             var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl }); |  | ||||||
|             var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); |  | ||||||
|             return new ChallengeResult(provider, properties); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null) |  | ||||||
|         { |  | ||||||
|             returnUrl = returnUrl ?? Url.Content("~/"); |  | ||||||
|             if (remoteError != null) |  | ||||||
|             { |  | ||||||
|                 ErrorMessage = $"Error from external provider: {remoteError}"; |  | ||||||
|                 return RedirectToPage("./Login", new { ReturnUrl = returnUrl }); |  | ||||||
|             } |  | ||||||
|             var info = await _signInManager.GetExternalLoginInfoAsync(); |  | ||||||
|             if (info == null) |  | ||||||
|             { |  | ||||||
|                 ErrorMessage = "Error loading external login information."; |  | ||||||
|                 return RedirectToPage("./Login", new { ReturnUrl = returnUrl }); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Sign in the user with this external login provider if the user already has a login. |  | ||||||
|             var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true); |  | ||||||
|             if (result.Succeeded) |  | ||||||
|             { |  | ||||||
|                 _logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider); |  | ||||||
|                 return LocalRedirect(returnUrl); |  | ||||||
|             } |  | ||||||
|             if (result.IsLockedOut) |  | ||||||
|             { |  | ||||||
|                 return RedirectToPage("./Lockout"); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 // If the user does not have an account, then ask the user to create an account. |  | ||||||
|                 ReturnUrl = returnUrl; |  | ||||||
|                 ProviderDisplayName = info.ProviderDisplayName; |  | ||||||
|                 if (info.Principal.HasClaim(c => c.Type == ClaimTypes.Email)) |  | ||||||
|                 { |  | ||||||
|                     Input = new InputModel |  | ||||||
|                     { |  | ||||||
|                         Email = info.Principal.FindFirstValue(ClaimTypes.Email) |  | ||||||
|                     }; |  | ||||||
|                 } |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null) |  | ||||||
|         { |  | ||||||
|             returnUrl = returnUrl ?? Url.Content("~/"); |  | ||||||
|             // Get the information about the user from the external login provider |  | ||||||
|             var info = await _signInManager.GetExternalLoginInfoAsync(); |  | ||||||
|             if (info == null) |  | ||||||
|             { |  | ||||||
|                 ErrorMessage = "Error loading external login information during confirmation."; |  | ||||||
|                 return RedirectToPage("./Login", new { ReturnUrl = returnUrl }); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (ModelState.IsValid) |  | ||||||
|             { |  | ||||||
|                 var user = CreateUser(); |  | ||||||
| 
 |  | ||||||
|                 await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); |  | ||||||
|                 await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); |  | ||||||
| 
 |  | ||||||
|                 var result = await _userManager.CreateAsync(user); |  | ||||||
|                 if (result.Succeeded) |  | ||||||
|                 { |  | ||||||
|                     result = await _userManager.AddLoginAsync(user, info); |  | ||||||
|                     if (result.Succeeded) |  | ||||||
|                     { |  | ||||||
|                         _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider); |  | ||||||
| 
 |  | ||||||
|                         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 }, |  | ||||||
|                             protocol: Request.Scheme); |  | ||||||
| 
 |  | ||||||
|                         await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", |  | ||||||
|                             $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); |  | ||||||
| 
 |  | ||||||
|                         // If account confirmation is required, we need to show the link if we don't have a real email sender |  | ||||||
|                         if (_userManager.Options.SignIn.RequireConfirmedAccount) |  | ||||||
|                         { |  | ||||||
|                             return RedirectToPage("./RegisterConfirmation", new { Email = Input.Email }); |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider); |  | ||||||
|                         return LocalRedirect(returnUrl); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 foreach (var error in result.Errors) |  | ||||||
|                 { |  | ||||||
|                     ModelState.AddModelError(string.Empty, error.Description); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             ProviderDisplayName = info.ProviderDisplayName; |  | ||||||
|             ReturnUrl = returnUrl; |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private IdentityUser CreateUser() |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 return Activator.CreateInstance<IdentityUser>(); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Can't create an instance of '{nameof(IdentityUser)}'. " + |  | ||||||
|                     $"Ensure that '{nameof(IdentityUser)}' is not an abstract class and has a parameterless constructor, or alternatively " + |  | ||||||
|                     $"override the external login page in /Areas/Identity/Pages/Account/ExternalLogin.cshtml"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private IUserEmailStore<IdentityUser> GetEmailStore() |  | ||||||
|         { |  | ||||||
|             if (!_userManager.SupportsUserEmail) |  | ||||||
|             { |  | ||||||
|                 throw new NotSupportedException("The default UI requires a user store with email support."); |  | ||||||
|             } |  | ||||||
|             return (IUserEmailStore<IdentityUser>)_userStore; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| @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" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" /> |  | ||||||
|                 <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" /> |  | ||||||
| } |  | ||||||
|  | @ -1,84 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Identity.UI.Services; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.AspNetCore.WebUtilities; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class ForgotPasswordModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly IEmailSender _emailSender; |  | ||||||
| 
 |  | ||||||
|         public ForgotPasswordModel(UserManager<IdentityUser> 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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ForgotPasswordConfirmation |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Forgot password confirmation"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h1>@ViewData["Title"]</h1> |  | ||||||
| <p> |  | ||||||
|     Please check your email to reset your password. |  | ||||||
| </p> |  | ||||||
|  | @ -1,25 +0,0 @@ | ||||||
| // 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 turf_tasker.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 ForgotPasswordConfirmation : 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() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| @page |  | ||||||
| @model LockoutModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Locked out"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <header> |  | ||||||
|     <h1 class="text-danger">@ViewData["Title"]</h1> |  | ||||||
|     <p class="text-danger">This account has been locked out, please try again later.</p> |  | ||||||
| </header> |  | ||||||
|  | @ -1,25 +0,0 @@ | ||||||
| // 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 turf_tasker.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 LockoutModel : 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() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,83 +0,0 @@ | ||||||
| @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" role="alert"></div> |  | ||||||
|                 <div class="form-floating mb-3"> |  | ||||||
|                     <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" /> |  | ||||||
|                     <label asp-for="Input.Email" class="form-label">Email</label> |  | ||||||
|                     <span asp-validation-for="Input.Email" class="text-danger"></span> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="form-floating mb-3"> |  | ||||||
|                     <input asp-for="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" /> |  | ||||||
|                     <label asp-for="Input.Password" class="form-label">Password</label> |  | ||||||
|                     <span asp-validation-for="Input.Password" class="text-danger"></span> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="checkbox mb-3"> |  | ||||||
|                     <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> |  | ||||||
|                     <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" /> |  | ||||||
| } |  | ||||||
|  | @ -1,140 +0,0 @@ | ||||||
| // 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 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 turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class LoginModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly ILogger<LoginModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public LoginModel(SignInManager<IdentityUser> 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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,39 +0,0 @@ | ||||||
| @page |  | ||||||
| @model LoginWith2faModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Two-factor authentication"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h1>@ViewData["Title"]</h1> |  | ||||||
| <hr /> |  | ||||||
| <p>Your login is protected with an authenticator app. Enter your authenticator code below.</p> |  | ||||||
| <div class="row"> |  | ||||||
|     <div class="col-md-4"> |  | ||||||
|         <form method="post" asp-route-returnUrl="@Model.ReturnUrl"> |  | ||||||
|             <input asp-for="RememberMe" type="hidden" /> |  | ||||||
|             <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.TwoFactorCode" class="form-control" autocomplete="off" /> |  | ||||||
|                 <label asp-for="Input.TwoFactorCode" class="form-label"></label> |  | ||||||
|                 <span asp-validation-for="Input.TwoFactorCode" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <div class="checkbox mb-3"> |  | ||||||
|                 <label asp-for="Input.RememberMachine" class="form-label"> |  | ||||||
|                     <input asp-for="Input.RememberMachine" /> |  | ||||||
|                     @Html.DisplayNameFor(m => m.Input.RememberMachine) |  | ||||||
|                 </label> |  | ||||||
|             </div> |  | ||||||
|             <div> |  | ||||||
|                 <button type="submit" class="w-100 btn btn-lg btn-primary">Log in</button> |  | ||||||
|             </div> |  | ||||||
|         </form> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| <p> |  | ||||||
|     Don't have access to your authenticator device? You can |  | ||||||
|     <a id="recovery-code-login" asp-page="./LoginWithRecoveryCode" asp-route-returnUrl="@Model.ReturnUrl">log in with a recovery code</a>. |  | ||||||
| </p> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,131 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class LoginWith2faModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly ILogger<LoginWith2faModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public LoginWith2faModel( |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             ILogger<LoginWith2faModel> logger) |  | ||||||
|         { |  | ||||||
|             _signInManager = signInManager; |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _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 bool RememberMe { 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 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(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] |  | ||||||
|             [DataType(DataType.Text)] |  | ||||||
|             [Display(Name = "Authenticator code")] |  | ||||||
|             public string TwoFactorCode { 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 this machine")] |  | ||||||
|             public bool RememberMachine { get; set; } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGetAsync(bool rememberMe, string returnUrl = null) |  | ||||||
|         { |  | ||||||
|             // Ensure the user has gone through the username & password screen first |  | ||||||
|             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); |  | ||||||
| 
 |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Unable to load two-factor authentication user."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             ReturnUrl = returnUrl; |  | ||||||
|             RememberMe = rememberMe; |  | ||||||
| 
 |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnPostAsync(bool rememberMe, string returnUrl = null) |  | ||||||
|         { |  | ||||||
|             if (!ModelState.IsValid) |  | ||||||
|             { |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             returnUrl = returnUrl ?? Url.Content("~/"); |  | ||||||
| 
 |  | ||||||
|             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Unable to load two-factor authentication user."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var authenticatorCode = Input.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty); |  | ||||||
| 
 |  | ||||||
|             var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, rememberMe, Input.RememberMachine); |  | ||||||
| 
 |  | ||||||
|             var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
| 
 |  | ||||||
|             if (result.Succeeded) |  | ||||||
|             { |  | ||||||
|                 _logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", user.Id); |  | ||||||
|                 return LocalRedirect(returnUrl); |  | ||||||
|             } |  | ||||||
|             else if (result.IsLockedOut) |  | ||||||
|             { |  | ||||||
|                 _logger.LogWarning("User with ID '{UserId}' account locked out.", user.Id); |  | ||||||
|                 return RedirectToPage("./Lockout"); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 _logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", user.Id); |  | ||||||
|                 ModelState.AddModelError(string.Empty, "Invalid authenticator code."); |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,29 +0,0 @@ | ||||||
| @page |  | ||||||
| @model LoginWithRecoveryCodeModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Recovery code verification"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h1>@ViewData["Title"]</h1> |  | ||||||
| <hr /> |  | ||||||
| <p> |  | ||||||
|     You have requested to log in with a recovery code. This login will not be remembered until you provide |  | ||||||
|     an authenticator app code at log in or disable 2FA and log in again. |  | ||||||
| </p> |  | ||||||
| <div class="row"> |  | ||||||
|     <div class="col-md-4"> |  | ||||||
|         <form method="post"> |  | ||||||
|             <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.RecoveryCode" class="form-control" autocomplete="off" placeholder="RecoveryCode" /> |  | ||||||
|                 <label asp-for="Input.RecoveryCode" class="form-label"></label> |  | ||||||
|                 <span asp-validation-for="Input.RecoveryCode" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <button type="submit" class="w-100 btn btn-lg btn-primary">Log in</button> |  | ||||||
|         </form> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,112 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class LoginWithRecoveryCodeModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly ILogger<LoginWithRecoveryCodeModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public LoginWithRecoveryCodeModel( |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             ILogger<LoginWithRecoveryCodeModel> logger) |  | ||||||
|         { |  | ||||||
|             _signInManager = signInManager; |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _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 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> |  | ||||||
|             [BindProperty] |  | ||||||
|             [Required] |  | ||||||
|             [DataType(DataType.Text)] |  | ||||||
|             [Display(Name = "Recovery Code")] |  | ||||||
|             public string RecoveryCode { get; set; } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGetAsync(string returnUrl = null) |  | ||||||
|         { |  | ||||||
|             // Ensure the user has gone through the username & password screen first |  | ||||||
|             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Unable to load two-factor authentication user."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             ReturnUrl = returnUrl; |  | ||||||
| 
 |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnPostAsync(string returnUrl = null) |  | ||||||
|         { |  | ||||||
|             if (!ModelState.IsValid) |  | ||||||
|             { |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Unable to load two-factor authentication user."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty); |  | ||||||
| 
 |  | ||||||
|             var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode); |  | ||||||
| 
 |  | ||||||
|             var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
| 
 |  | ||||||
|             if (result.Succeeded) |  | ||||||
|             { |  | ||||||
|                 _logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", user.Id); |  | ||||||
|                 return LocalRedirect(returnUrl ?? Url.Content("~/")); |  | ||||||
|             } |  | ||||||
|             if (result.IsLockedOut) |  | ||||||
|             { |  | ||||||
|                 _logger.LogWarning("User account locked out."); |  | ||||||
|                 return RedirectToPage("./Lockout"); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 _logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", user.Id); |  | ||||||
|                 ModelState.AddModelError(string.Empty, "Invalid recovery code entered."); |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,21 +0,0 @@ | ||||||
| @page |  | ||||||
| @model LogoutModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Log out"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <header> |  | ||||||
|     <h1>@ViewData["Title"]</h1> |  | ||||||
|     @{ |  | ||||||
|         if (User.Identity?.IsAuthenticated ?? false) |  | ||||||
|         { |  | ||||||
|             <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> |  | ||||||
|  | @ -1,42 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class LogoutModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly ILogger<LogoutModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public LogoutModel(SignInManager<IdentityUser> 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(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,36 +0,0 @@ | ||||||
| @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" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.OldPassword" class="form-control" autocomplete="current-password" aria-required="true" placeholder="Please enter your old password." /> |  | ||||||
|                 <label asp-for="Input.OldPassword" class="form-label"></label> |  | ||||||
|                 <span asp-validation-for="Input.OldPassword" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.NewPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="Please enter your 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 mb-3"> |  | ||||||
|                 <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="Please confirm your 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">Update password</button> |  | ||||||
|         </form> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,127 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class ChangePasswordModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly ILogger<ChangePasswordModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public ChangePasswordModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             SignInManager<IdentityUser> 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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,33 +0,0 @@ | ||||||
| @page |  | ||||||
| @model DeletePersonalDataModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Delete Personal Data"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.PersonalData; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| 
 |  | ||||||
| <div class="alert alert-warning" role="alert"> |  | ||||||
|     <p> |  | ||||||
|         <strong>Deleting this data will permanently remove your account, and this cannot be recovered.</strong> |  | ||||||
|     </p> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| <div> |  | ||||||
|     <form id="delete-user" method="post"> |  | ||||||
|         <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> |  | ||||||
|         @if (Model.RequirePassword) |  | ||||||
|         { |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="Please enter your password." /> |  | ||||||
|                 <label asp-for="Input.Password" class="form-label"></label> |  | ||||||
|                 <span asp-validation-for="Input.Password" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|         } |  | ||||||
|         <button class="w-100 btn btn-lg btn-danger" type="submit">Delete data and close my account</button> |  | ||||||
|     </form> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,103 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class DeletePersonalDataModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly ILogger<DeletePersonalDataModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public DeletePersonalDataModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             ILogger<DeletePersonalDataModel> 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> |  | ||||||
|         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)] |  | ||||||
|             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> |  | ||||||
|         public bool RequirePassword { get; set; } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGet() |  | ||||||
|         { |  | ||||||
|             var user = await _userManager.GetUserAsync(User); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             RequirePassword = await _userManager.HasPasswordAsync(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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             RequirePassword = await _userManager.HasPasswordAsync(user); |  | ||||||
|             if (RequirePassword) |  | ||||||
|             { |  | ||||||
|                 if (!await _userManager.CheckPasswordAsync(user, Input.Password)) |  | ||||||
|                 { |  | ||||||
|                     ModelState.AddModelError(string.Empty, "Incorrect password."); |  | ||||||
|                     return Page(); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var result = await _userManager.DeleteAsync(user); |  | ||||||
|             var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|             if (!result.Succeeded) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Unexpected error occurred deleting user."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             await _signInManager.SignOutAsync(); |  | ||||||
| 
 |  | ||||||
|             _logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId); |  | ||||||
| 
 |  | ||||||
|             return Redirect("~/"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,25 +0,0 @@ | ||||||
| @page |  | ||||||
| @model Disable2faModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Disable two-factor authentication (2FA)"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| 
 |  | ||||||
| <div class="alert alert-warning" role="alert"> |  | ||||||
|     <p> |  | ||||||
|         <strong>This action only disables 2FA.</strong> |  | ||||||
|     </p> |  | ||||||
|     <p> |  | ||||||
|         Disabling 2FA does not change the keys used in authenticator apps. If you wish to change the key |  | ||||||
|         used in an authenticator app you should <a asp-page="./ResetAuthenticator">reset your authenticator keys.</a> |  | ||||||
|     </p> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| <div> |  | ||||||
|     <form method="post"> |  | ||||||
|         <button class="btn btn-danger" type="submit">Disable 2FA</button> |  | ||||||
|     </form> |  | ||||||
| </div> |  | ||||||
|  | @ -1,69 +0,0 @@ | ||||||
| // 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.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class Disable2faModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly ILogger<Disable2faModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public Disable2faModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             ILogger<Disable2faModel> logger) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _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> |  | ||||||
|         [TempData] |  | ||||||
|         public string StatusMessage { get; set; } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGet() |  | ||||||
|         { |  | ||||||
|             var user = await _userManager.GetUserAsync(User); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (!await _userManager.GetTwoFactorEnabledAsync(user)) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Cannot disable 2FA for user as it's not currently enabled."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var disable2faResult = await _userManager.SetTwoFactorEnabledAsync(user, false); |  | ||||||
|             if (!disable2faResult.Succeeded) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Unexpected error occurred disabling 2FA."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             _logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", _userManager.GetUserId(User)); |  | ||||||
|             StatusMessage = "2fa has been disabled. You can reenable 2fa when you setup an authenticator app"; |  | ||||||
|             return RedirectToPage("./TwoFactorAuthentication"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,12 +0,0 @@ | ||||||
| @page |  | ||||||
| @model DownloadPersonalDataModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Download Your Data"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.PersonalData; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,67 +0,0 @@ | ||||||
| // 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.Linq; |  | ||||||
| using System.Text; |  | ||||||
| using System.Text.Json; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class DownloadPersonalDataModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly ILogger<DownloadPersonalDataModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public DownloadPersonalDataModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             ILogger<DownloadPersonalDataModel> logger) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _logger = logger; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public IActionResult OnGet() |  | ||||||
|         { |  | ||||||
|             return NotFound(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             _logger.LogInformation("User with ID '{UserId}' asked for their personal data.", _userManager.GetUserId(User)); |  | ||||||
| 
 |  | ||||||
|             // Only include personal data for download |  | ||||||
|             var personalData = new Dictionary<string, string>(); |  | ||||||
|             var personalDataProps = typeof(IdentityUser).GetProperties().Where( |  | ||||||
|                             prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute))); |  | ||||||
|             foreach (var p in personalDataProps) |  | ||||||
|             { |  | ||||||
|                 personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null"); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var logins = await _userManager.GetLoginsAsync(user); |  | ||||||
|             foreach (var l in logins) |  | ||||||
|             { |  | ||||||
|                 personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             personalData.Add($"Authenticator Key", await _userManager.GetAuthenticatorKeyAsync(user)); |  | ||||||
| 
 |  | ||||||
|             Response.Headers.TryAdd("Content-Disposition", "attachment; filename=PersonalData.json"); |  | ||||||
|             return new FileContentResult(JsonSerializer.SerializeToUtf8Bytes(personalData), "application/json"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,44 +0,0 @@ | ||||||
| @page |  | ||||||
| @model EmailModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Manage Email"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.Email; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| <div class="row"> |  | ||||||
|     <div class="col-md-6"> |  | ||||||
|         <form id="email-form" method="post"> |  | ||||||
|             <div asp-validation-summary="All" class="text-danger" role="alert"></div> |  | ||||||
|             @if (Model.IsEmailConfirmed) |  | ||||||
|             { |  | ||||||
|                 <div class="form-floating mb-3 input-group"> |  | ||||||
|                     <input asp-for="Email" class="form-control" placeholder="Please enter your email." disabled /> |  | ||||||
|                         <div class="input-group-append"> |  | ||||||
|                             <span class="h-100 input-group-text text-success font-weight-bold">✓</span> |  | ||||||
|                         </div> |  | ||||||
|                     <label asp-for="Email" class="form-label"></label> |  | ||||||
|                 </div> |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 <div class="form-floating mb-3"> |  | ||||||
|                     <input asp-for="Email" class="form-control" placeholder="Please enter your email." disabled /> |  | ||||||
|                     <label asp-for="Email" class="form-label"></label> |  | ||||||
|                     <button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button> |  | ||||||
|                 </div> |  | ||||||
|             } |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.NewEmail" class="form-control" autocomplete="email" aria-required="true" placeholder="Please enter new email." /> |  | ||||||
|                 <label asp-for="Input.NewEmail" class="form-label"></label> |  | ||||||
|                 <span asp-validation-for="Input.NewEmail" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <button id="change-email-button" type="submit" asp-page-handler="ChangeEmail" class="w-100 btn btn-lg btn-primary">Change email</button> |  | ||||||
|         </form> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,171 +0,0 @@ | ||||||
| // 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.Identity; |  | ||||||
| using Microsoft.AspNetCore.Identity.UI.Services; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.AspNetCore.WebUtilities; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class EmailModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly IEmailSender _emailSender; |  | ||||||
| 
 |  | ||||||
|         public EmailModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             IEmailSender emailSender) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _signInManager = signInManager; |  | ||||||
|             _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> |  | ||||||
|         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> |  | ||||||
|         public bool IsEmailConfirmed { 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> |  | ||||||
|             [Required] |  | ||||||
|             [EmailAddress] |  | ||||||
|             [Display(Name = "New email")] |  | ||||||
|             public string NewEmail { get; set; } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private async Task LoadAsync(IdentityUser user) |  | ||||||
|         { |  | ||||||
|             var email = await _userManager.GetEmailAsync(user); |  | ||||||
|             Email = email; |  | ||||||
| 
 |  | ||||||
|             Input = new InputModel |  | ||||||
|             { |  | ||||||
|                 NewEmail = email, |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         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> OnPostChangeEmailAsync() |  | ||||||
|         { |  | ||||||
|             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 email = await _userManager.GetEmailAsync(user); |  | ||||||
|             if (Input.NewEmail != email) |  | ||||||
|             { |  | ||||||
|                 var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|                 var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); |  | ||||||
|                 code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); |  | ||||||
|                 var callbackUrl = Url.Page( |  | ||||||
|                     "/Account/ConfirmEmailChange", |  | ||||||
|                     pageHandler: null, |  | ||||||
|                     values: new { area = "Identity", userId = userId, email = Input.NewEmail, code = code }, |  | ||||||
|                     protocol: Request.Scheme); |  | ||||||
|                 await _emailSender.SendEmailAsync( |  | ||||||
|                     Input.NewEmail, |  | ||||||
|                     "Confirm your email", |  | ||||||
|                     $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); |  | ||||||
| 
 |  | ||||||
|                 StatusMessage = "Confirmation link to change email sent. Please check your email."; |  | ||||||
|                 return RedirectToPage(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             StatusMessage = "Your email is unchanged."; |  | ||||||
|             return RedirectToPage(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnPostSendVerificationEmailAsync() |  | ||||||
|         { |  | ||||||
|             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 userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|             var email = await _userManager.GetEmailAsync(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 }, |  | ||||||
|                 protocol: Request.Scheme); |  | ||||||
|             await _emailSender.SendEmailAsync( |  | ||||||
|                 email, |  | ||||||
|                 "Confirm your email", |  | ||||||
|                 $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); |  | ||||||
| 
 |  | ||||||
|             StatusMessage = "Verification email sent. Please check your email."; |  | ||||||
|             return RedirectToPage(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,53 +0,0 @@ | ||||||
| @page |  | ||||||
| @model EnableAuthenticatorModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Configure authenticator app"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| <div> |  | ||||||
|     <p>To use an authenticator app go through the following steps:</p> |  | ||||||
|     <ol class="list"> |  | ||||||
|         <li> |  | ||||||
|             <p> |  | ||||||
|                 Download a two-factor authenticator app like Microsoft Authenticator for |  | ||||||
|                 <a href="https://go.microsoft.com/fwlink/?Linkid=825072">Android</a> and |  | ||||||
|                 <a href="https://go.microsoft.com/fwlink/?Linkid=825073">iOS</a> or |  | ||||||
|                 Google Authenticator for |  | ||||||
|                 <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en">Android</a> and |  | ||||||
|                 <a href="https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8">iOS</a>. |  | ||||||
|             </p> |  | ||||||
|         </li> |  | ||||||
|         <li> |  | ||||||
|             <p>Scan the QR Code or enter this key <kbd>@Model.SharedKey</kbd> into your two factor authenticator app. Spaces and casing do not matter.</p> |  | ||||||
|             <div class="alert alert-info">Learn how to <a href="https://go.microsoft.com/fwlink/?Linkid=852423">enable QR code generation</a>.</div> |  | ||||||
|             <div id="qrCode"></div> |  | ||||||
|             <div id="qrCodeData" data-url="@Model.AuthenticatorUri"></div> |  | ||||||
|         </li> |  | ||||||
|         <li> |  | ||||||
|             <p> |  | ||||||
|                 Once you have scanned the QR code or input the key above, your two factor authentication app will provide you |  | ||||||
|                 with a unique code. Enter the code in the confirmation box below. |  | ||||||
|             </p> |  | ||||||
|             <div class="row"> |  | ||||||
|                 <div class="col-md-6"> |  | ||||||
|                     <form id="send-code" method="post"> |  | ||||||
|                         <div class="form-floating mb-3"> |  | ||||||
|                             <input asp-for="Input.Code" class="form-control" autocomplete="off" placeholder="Please enter the code."/> |  | ||||||
|                             <label asp-for="Input.Code" class="control-label form-label">Verification Code</label> |  | ||||||
|                             <span asp-validation-for="Input.Code" class="text-danger"></span> |  | ||||||
|                         </div> |  | ||||||
|                         <button type="submit" class="w-100 btn btn-lg btn-primary">Verify</button> |  | ||||||
|                         <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> |  | ||||||
|                     </form> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|         </li> |  | ||||||
|     </ol> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,188 +0,0 @@ | ||||||
| // 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.Globalization; |  | ||||||
| using System.Linq; |  | ||||||
| using System.Text; |  | ||||||
| using System.Text.Encodings.Web; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class EnableAuthenticatorModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly ILogger<EnableAuthenticatorModel> _logger; |  | ||||||
|         private readonly UrlEncoder _urlEncoder; |  | ||||||
| 
 |  | ||||||
|         private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6"; |  | ||||||
| 
 |  | ||||||
|         public EnableAuthenticatorModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             ILogger<EnableAuthenticatorModel> logger, |  | ||||||
|             UrlEncoder urlEncoder) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _logger = logger; |  | ||||||
|             _urlEncoder = urlEncoder; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <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 SharedKey { 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 AuthenticatorUri { 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[] RecoveryCodes { 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> |  | ||||||
|             [Required] |  | ||||||
|             [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] |  | ||||||
|             [DataType(DataType.Text)] |  | ||||||
|             [Display(Name = "Verification Code")] |  | ||||||
|             public string Code { 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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             await LoadSharedKeyAndQrCodeUriAsync(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 LoadSharedKeyAndQrCodeUriAsync(user); |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Strip spaces and hyphens |  | ||||||
|             var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty); |  | ||||||
| 
 |  | ||||||
|             var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync( |  | ||||||
|                 user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode); |  | ||||||
| 
 |  | ||||||
|             if (!is2faTokenValid) |  | ||||||
|             { |  | ||||||
|                 ModelState.AddModelError("Input.Code", "Verification code is invalid."); |  | ||||||
|                 await LoadSharedKeyAndQrCodeUriAsync(user); |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             await _userManager.SetTwoFactorEnabledAsync(user, true); |  | ||||||
|             var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|             _logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", userId); |  | ||||||
| 
 |  | ||||||
|             StatusMessage = "Your authenticator app has been verified."; |  | ||||||
| 
 |  | ||||||
|             if (await _userManager.CountRecoveryCodesAsync(user) == 0) |  | ||||||
|             { |  | ||||||
|                 var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); |  | ||||||
|                 RecoveryCodes = recoveryCodes.ToArray(); |  | ||||||
|                 return RedirectToPage("./ShowRecoveryCodes"); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return RedirectToPage("./TwoFactorAuthentication"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private async Task LoadSharedKeyAndQrCodeUriAsync(IdentityUser user) |  | ||||||
|         { |  | ||||||
|             // Load the authenticator key & QR code URI to display on the form |  | ||||||
|             var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user); |  | ||||||
|             if (string.IsNullOrEmpty(unformattedKey)) |  | ||||||
|             { |  | ||||||
|                 await _userManager.ResetAuthenticatorKeyAsync(user); |  | ||||||
|                 unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             SharedKey = FormatKey(unformattedKey); |  | ||||||
| 
 |  | ||||||
|             var email = await _userManager.GetEmailAsync(user); |  | ||||||
|             AuthenticatorUri = GenerateQrCodeUri(email, unformattedKey); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private string FormatKey(string unformattedKey) |  | ||||||
|         { |  | ||||||
|             var result = new StringBuilder(); |  | ||||||
|             int currentPosition = 0; |  | ||||||
|             while (currentPosition + 4 < unformattedKey.Length) |  | ||||||
|             { |  | ||||||
|                 result.Append(unformattedKey.AsSpan(currentPosition, 4)).Append(' '); |  | ||||||
|                 currentPosition += 4; |  | ||||||
|             } |  | ||||||
|             if (currentPosition < unformattedKey.Length) |  | ||||||
|             { |  | ||||||
|                 result.Append(unformattedKey.AsSpan(currentPosition)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return result.ToString().ToLowerInvariant(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private string GenerateQrCodeUri(string email, string unformattedKey) |  | ||||||
|         { |  | ||||||
|             return string.Format( |  | ||||||
|                 CultureInfo.InvariantCulture, |  | ||||||
|                 AuthenticatorUriFormat, |  | ||||||
|                 _urlEncoder.Encode("Microsoft.AspNetCore.Identity.UI"), |  | ||||||
|                 _urlEncoder.Encode(email), |  | ||||||
|                 unformattedKey); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,53 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ExternalLoginsModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Manage your external logins"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.ExternalLogins; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| @if (Model.CurrentLogins?.Count > 0) |  | ||||||
| { |  | ||||||
|     <h3>Registered Logins</h3> |  | ||||||
|     <table class="table"> |  | ||||||
|         <tbody> |  | ||||||
|             @foreach (var login in Model.CurrentLogins) |  | ||||||
|             { |  | ||||||
|                 <tr> |  | ||||||
|                     <td id="@($"login-provider-{login.LoginProvider}")">@login.ProviderDisplayName</td> |  | ||||||
|                     <td> |  | ||||||
|                         @if (Model.ShowRemoveButton) |  | ||||||
|                         { |  | ||||||
|                             <form id="@($"remove-login-{login.LoginProvider}")" asp-page-handler="RemoveLogin" method="post"> |  | ||||||
|                                 <div> |  | ||||||
|                                     <input asp-for="@login.LoginProvider" name="LoginProvider" type="hidden" /> |  | ||||||
|                                     <input asp-for="@login.ProviderKey" name="ProviderKey" type="hidden" /> |  | ||||||
|                                     <button type="submit" class="btn btn-primary" title="Remove this @login.ProviderDisplayName login from your account">Remove</button> |  | ||||||
|                                 </div> |  | ||||||
|                             </form> |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             @:   |  | ||||||
|                         } |  | ||||||
|                     </td> |  | ||||||
|                 </tr> |  | ||||||
|             } |  | ||||||
|         </tbody> |  | ||||||
|     </table> |  | ||||||
| } |  | ||||||
| @if (Model.OtherLogins?.Count > 0) |  | ||||||
| { |  | ||||||
|     <h4>Add another service to log in.</h4> |  | ||||||
|     <hr /> |  | ||||||
|     <form id="link-login-form" asp-page-handler="LinkLogin" method="post" class="form-horizontal"> |  | ||||||
|         <div id="socialLoginList"> |  | ||||||
|             <p> |  | ||||||
|                 @foreach (var provider in Model.OtherLogins) |  | ||||||
|                 { |  | ||||||
|                     <button id="@($"link-login-button-{provider.Name}")" 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> |  | ||||||
| } |  | ||||||
|  | @ -1,141 +0,0 @@ | ||||||
| // 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.Linq; |  | ||||||
| using System.Threading; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Authentication; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class ExternalLoginsModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly IUserStore<IdentityUser> _userStore; |  | ||||||
| 
 |  | ||||||
|         public ExternalLoginsModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             IUserStore<IdentityUser> userStore) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _signInManager = signInManager; |  | ||||||
|             _userStore = userStore; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <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<UserLoginInfo> CurrentLogins { 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> OtherLogins { 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 bool ShowRemoveButton { 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; } |  | ||||||
| 
 |  | ||||||
|         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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             CurrentLogins = await _userManager.GetLoginsAsync(user); |  | ||||||
|             OtherLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()) |  | ||||||
|                 .Where(auth => CurrentLogins.All(ul => auth.Name != ul.LoginProvider)) |  | ||||||
|                 .ToList(); |  | ||||||
| 
 |  | ||||||
|             string passwordHash = null; |  | ||||||
|             if (_userStore is IUserPasswordStore<IdentityUser> userPasswordStore) |  | ||||||
|             { |  | ||||||
|                 passwordHash = await userPasswordStore.GetPasswordHashAsync(user, HttpContext.RequestAborted); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             ShowRemoveButton = passwordHash != null || CurrentLogins.Count > 1; |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnPostRemoveLoginAsync(string loginProvider, string providerKey) |  | ||||||
|         { |  | ||||||
|             var user = await _userManager.GetUserAsync(User); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var result = await _userManager.RemoveLoginAsync(user, loginProvider, providerKey); |  | ||||||
|             if (!result.Succeeded) |  | ||||||
|             { |  | ||||||
|                 StatusMessage = "The external login was not removed."; |  | ||||||
|                 return RedirectToPage(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             await _signInManager.RefreshSignInAsync(user); |  | ||||||
|             StatusMessage = "The external login was removed."; |  | ||||||
|             return RedirectToPage(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnPostLinkLoginAsync(string provider) |  | ||||||
|         { |  | ||||||
|             // Clear the existing external cookie to ensure a clean login process |  | ||||||
|             await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); |  | ||||||
| 
 |  | ||||||
|             // Request a redirect to the external login provider to link a login for the current user |  | ||||||
|             var redirectUrl = Url.Page("./ExternalLogins", pageHandler: "LinkLoginCallback"); |  | ||||||
|             var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); |  | ||||||
|             return new ChallengeResult(provider, properties); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGetLinkLoginCallbackAsync() |  | ||||||
|         { |  | ||||||
|             var user = await _userManager.GetUserAsync(User); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|             var info = await _signInManager.GetExternalLoginInfoAsync(userId); |  | ||||||
|             if (info == null) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Unexpected error occurred loading external login info."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var result = await _userManager.AddLoginAsync(user, info); |  | ||||||
|             if (!result.Succeeded) |  | ||||||
|             { |  | ||||||
|                 StatusMessage = "The external login was not added. External logins can only be associated with one account."; |  | ||||||
|                 return RedirectToPage(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Clear the existing external cookie to ensure a clean login process |  | ||||||
|             await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); |  | ||||||
| 
 |  | ||||||
|             StatusMessage = "The external login was added."; |  | ||||||
|             return RedirectToPage(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,27 +0,0 @@ | ||||||
| @page |  | ||||||
| @model GenerateRecoveryCodesModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Generate two-factor authentication (2FA) recovery codes"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| <div class="alert alert-warning" role="alert"> |  | ||||||
|     <p> |  | ||||||
|         <span class="glyphicon glyphicon-warning-sign"></span> |  | ||||||
|         <strong>Put these codes in a safe place.</strong> |  | ||||||
|     </p> |  | ||||||
|     <p> |  | ||||||
|         If you lose your device and don't have the recovery codes you will lose access to your account. |  | ||||||
|     </p> |  | ||||||
|     <p> |  | ||||||
|         Generating new recovery codes does not change the keys used in authenticator apps. If you wish to change the key |  | ||||||
|         used in an authenticator app you should <a asp-page="./ResetAuthenticator">reset your authenticator keys.</a> |  | ||||||
|     </p> |  | ||||||
| </div> |  | ||||||
| <div> |  | ||||||
|     <form method="post"> |  | ||||||
|         <button class="btn btn-danger" type="submit">Generate Recovery Codes</button> |  | ||||||
|     </form> |  | ||||||
| </div> |  | ||||||
|  | @ -1,82 +0,0 @@ | ||||||
| // 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.Linq; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class GenerateRecoveryCodesModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly ILogger<GenerateRecoveryCodesModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public GenerateRecoveryCodesModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             ILogger<GenerateRecoveryCodesModel> logger) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _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> |  | ||||||
|         [TempData] |  | ||||||
|         public string[] RecoveryCodes { 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; } |  | ||||||
| 
 |  | ||||||
|         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 isTwoFactorEnabled = await _userManager.GetTwoFactorEnabledAsync(user); |  | ||||||
|             if (!isTwoFactorEnabled) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Cannot generate recovery codes for user because they do not have 2FA enabled."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var isTwoFactorEnabled = await _userManager.GetTwoFactorEnabledAsync(user); |  | ||||||
|             var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|             if (!isTwoFactorEnabled) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Cannot generate recovery codes for user as they do not have 2FA enabled."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); |  | ||||||
|             RecoveryCodes = recoveryCodes.ToArray(); |  | ||||||
| 
 |  | ||||||
|             _logger.LogInformation("User with ID '{UserId}' has generated new 2FA recovery codes.", userId); |  | ||||||
|             StatusMessage = "You have generated new recovery codes."; |  | ||||||
|             return RedirectToPage("./ShowRecoveryCodes"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,30 +0,0 @@ | ||||||
| @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" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Username" class="form-control" placeholder="Please choose your username." disabled /> |  | ||||||
|                 <label asp-for="Username" class="form-label"></label> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.PhoneNumber" class="form-control" placeholder="Please enter your phone number."/> |  | ||||||
|                 <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" /> |  | ||||||
| } |  | ||||||
|  | @ -1,118 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class IndexModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
| 
 |  | ||||||
|         public IndexModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             SignInManager<IdentityUser> 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(IdentityUser 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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,123 +0,0 @@ | ||||||
| // 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  turf_tasker.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; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,27 +0,0 @@ | ||||||
| @page |  | ||||||
| @model PersonalDataModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Personal Data"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.PersonalData; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| 
 |  | ||||||
| <div class="row"> |  | ||||||
|     <div class="col-md-6"> |  | ||||||
|         <p>Your account contains personal data that you have given us. This page allows you to download or delete that data.</p> |  | ||||||
|         <p> |  | ||||||
|             <strong>Deleting this data will permanently remove your account, and this cannot be recovered.</strong> |  | ||||||
|         </p> |  | ||||||
|         <form id="download-data" asp-page="DownloadPersonalData" method="post"> |  | ||||||
|             <button class="btn btn-primary" type="submit">Download</button> |  | ||||||
|         </form> |  | ||||||
|         <p> |  | ||||||
|             <a id="delete" asp-page="DeletePersonalData" class="btn btn-danger">Delete</a> |  | ||||||
|         </p> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,36 +0,0 @@ | ||||||
| // Licensed to the .NET Foundation under one or more agreements. |  | ||||||
| // The .NET Foundation licenses this file to you under the MIT license. |  | ||||||
| using System; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class PersonalDataModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly ILogger<PersonalDataModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public PersonalDataModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             ILogger<PersonalDataModel> logger) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _logger = logger; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGet() |  | ||||||
|         { |  | ||||||
|             var user = await _userManager.GetUserAsync(User); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,24 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ResetAuthenticatorModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Reset authenticator key"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| <div class="alert alert-warning" role="alert"> |  | ||||||
|     <p> |  | ||||||
|         <span class="glyphicon glyphicon-warning-sign"></span> |  | ||||||
|         <strong>If you reset your authenticator key your authenticator app will not work until you reconfigure it.</strong> |  | ||||||
|     </p> |  | ||||||
|     <p> |  | ||||||
|         This process disables 2FA until you verify your authenticator app. |  | ||||||
|         If you do not complete your authenticator app configuration you may lose access to your account. |  | ||||||
|     </p> |  | ||||||
| </div> |  | ||||||
| <div> |  | ||||||
|     <form id="reset-authenticator-form" method="post"> |  | ||||||
|         <button id="reset-authenticator-button" class="btn btn-danger" type="submit">Reset authenticator key</button> |  | ||||||
|     </form> |  | ||||||
| </div> |  | ||||||
|  | @ -1,67 +0,0 @@ | ||||||
| // 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.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class ResetAuthenticatorModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly ILogger<ResetAuthenticatorModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public ResetAuthenticatorModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             ILogger<ResetAuthenticatorModel> 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> |  | ||||||
|         [TempData] |  | ||||||
|         public string StatusMessage { get; set; } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGet() |  | ||||||
|         { |  | ||||||
|             var user = await _userManager.GetUserAsync(User); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             await _userManager.SetTwoFactorEnabledAsync(user, false); |  | ||||||
|             await _userManager.ResetAuthenticatorKeyAsync(user); |  | ||||||
|             var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|             _logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", user.Id); |  | ||||||
| 
 |  | ||||||
|             await _signInManager.RefreshSignInAsync(user); |  | ||||||
|             StatusMessage = "Your authenticator app key has been reset, you will need to configure your authenticator app using the new key."; |  | ||||||
| 
 |  | ||||||
|             return RedirectToPage("./EnableAuthenticator"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,35 +0,0 @@ | ||||||
| @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" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.NewPassword" class="form-control" autocomplete="new-password" placeholder="Please enter your 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 mb-3"> |  | ||||||
|                 <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" placeholder="Please confirm your 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" /> |  | ||||||
| } |  | ||||||
|  | @ -1,114 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class SetPasswordModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
| 
 |  | ||||||
|         public SetPasswordModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             SignInManager<IdentityUser> 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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,25 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ShowRecoveryCodesModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Recovery codes"; |  | ||||||
|     ViewData["ActivePage"] = "TwoFactorAuthentication"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| <div class="alert alert-warning" role="alert"> |  | ||||||
|     <p> |  | ||||||
|         <strong>Put these codes in a safe place.</strong> |  | ||||||
|     </p> |  | ||||||
|     <p> |  | ||||||
|         If you lose your device and don't have the recovery codes you will lose access to your account. |  | ||||||
|     </p> |  | ||||||
| </div> |  | ||||||
| <div class="row"> |  | ||||||
|     <div class="col-md-12"> |  | ||||||
|         @for (var row = 0; row < Model.RecoveryCodes.Length; row += 2) |  | ||||||
|         { |  | ||||||
|             <code class="recovery-code">@Model.RecoveryCodes[row]</code><text> </text><code class="recovery-code">@Model.RecoveryCodes[row + 1]</code><br /> |  | ||||||
|         } |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
|  | @ -1,46 +0,0 @@ | ||||||
| // 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.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.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 class ShowRecoveryCodesModel : 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> |  | ||||||
|         [TempData] |  | ||||||
|         public string[] RecoveryCodes { 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 IActionResult OnGet() |  | ||||||
|         { |  | ||||||
|             if (RecoveryCodes == null || RecoveryCodes.Length == 0) |  | ||||||
|             { |  | ||||||
|                 return RedirectToPage("./TwoFactorAuthentication"); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,71 +0,0 @@ | ||||||
| @page |  | ||||||
| @using Microsoft.AspNetCore.Http.Features |  | ||||||
| @model TwoFactorAuthenticationModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Two-factor authentication (2FA)"; |  | ||||||
|     ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <partial name="_StatusMessage" for="StatusMessage" /> |  | ||||||
| <h3>@ViewData["Title"]</h3> |  | ||||||
| @{ |  | ||||||
|     var consentFeature = HttpContext.Features.Get<ITrackingConsentFeature>(); |  | ||||||
|     @if (consentFeature?.CanTrack ?? true) |  | ||||||
|     { |  | ||||||
|         @if (Model.Is2faEnabled) |  | ||||||
|         { |  | ||||||
|             if (Model.RecoveryCodesLeft == 0) |  | ||||||
|             { |  | ||||||
|                 <div class="alert alert-danger"> |  | ||||||
|                     <strong>You have no recovery codes left.</strong> |  | ||||||
|                     <p>You must <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a> before you can log in with a recovery code.</p> |  | ||||||
|                 </div> |  | ||||||
|             } |  | ||||||
|             else if (Model.RecoveryCodesLeft == 1) |  | ||||||
|             { |  | ||||||
|                 <div class="alert alert-danger"> |  | ||||||
|                     <strong>You have 1 recovery code left.</strong> |  | ||||||
|                     <p>You can <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p> |  | ||||||
|                 </div> |  | ||||||
|             } |  | ||||||
|             else if (Model.RecoveryCodesLeft <= 3) |  | ||||||
|             { |  | ||||||
|                 <div class="alert alert-warning"> |  | ||||||
|                     <strong>You have @Model.RecoveryCodesLeft recovery codes left.</strong> |  | ||||||
|                     <p>You should <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p> |  | ||||||
|                 </div> |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (Model.IsMachineRemembered) |  | ||||||
|             { |  | ||||||
|                 <form method="post" style="display: inline-block"> |  | ||||||
|                     <button type="submit" class="btn btn-primary">Forget this browser</button> |  | ||||||
|                 </form> |  | ||||||
|             } |  | ||||||
|             <a asp-page="./Disable2fa" class="btn btn-primary">Disable 2FA</a> |  | ||||||
|             <a asp-page="./GenerateRecoveryCodes" class="btn btn-primary">Reset recovery codes</a> |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         <h4>Authenticator app</h4> |  | ||||||
|         @if (!Model.HasAuthenticator) |  | ||||||
|         { |  | ||||||
|             <a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Add authenticator app</a> |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             <a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Set up authenticator app</a> |  | ||||||
|             <a id="reset-authenticator" asp-page="./ResetAuthenticator" class="btn btn-primary">Reset authenticator app</a> |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         <div class="alert alert-danger"> |  | ||||||
|             <strong>Privacy and cookie policy have not been accepted.</strong> |  | ||||||
|             <p>You must accept the policy before you can enable two factor authentication.</p> |  | ||||||
|         </div> |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,89 +0,0 @@ | ||||||
| // 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.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
| { |  | ||||||
|     public class TwoFactorAuthenticationModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly ILogger<TwoFactorAuthenticationModel> _logger; |  | ||||||
| 
 |  | ||||||
|         public TwoFactorAuthenticationModel( |  | ||||||
|             UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager, ILogger<TwoFactorAuthenticationModel> 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> |  | ||||||
|         public bool HasAuthenticator { 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 int RecoveryCodesLeft { 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 bool Is2faEnabled { 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 bool IsMachineRemembered { 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; } |  | ||||||
| 
 |  | ||||||
|         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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             HasAuthenticator = await _userManager.GetAuthenticatorKeyAsync(user) != null; |  | ||||||
|             Is2faEnabled = await _userManager.GetTwoFactorEnabledAsync(user); |  | ||||||
|             IsMachineRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user); |  | ||||||
|             RecoveryCodesLeft = await _userManager.CountRecoveryCodesAsync(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)}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             await _signInManager.ForgetTwoFactorClientAsync(); |  | ||||||
|             StatusMessage = "The current browser has been forgotten. When you login again from this browser you will be prompted for your 2fa code."; |  | ||||||
|             return RedirectToPage(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,29 +0,0 @@ | ||||||
| @{ |  | ||||||
|     if (ViewData.TryGetValue("ParentLayout", out var parentLayout) && parentLayout !=  null) |  | ||||||
|     { |  | ||||||
|         Layout = parentLayout.ToString(); |  | ||||||
|     } |  | ||||||
|     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) |  | ||||||
| } |  | ||||||
|  | @ -1,15 +0,0 @@ | ||||||
| @inject SignInManager<IdentityUser> 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> |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| @model string |  | ||||||
| 
 |  | ||||||
| @if (!String.IsNullOrEmpty(Model)) |  | ||||||
| { |  | ||||||
|     var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success"; |  | ||||||
|     <div class="alert alert-@statusMessageClass alert-dismissible" role="alert"> |  | ||||||
|         <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> |  | ||||||
|         @Model |  | ||||||
|     </div> |  | ||||||
| } |  | ||||||
|  | @ -1 +0,0 @@ | ||||||
| @using turf_tasker.Areas.Identity.Pages.Account.Manage |  | ||||||
|  | @ -1,67 +0,0 @@ | ||||||
| @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" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" /> |  | ||||||
|                 <label asp-for="Input.Email">Email</label> |  | ||||||
|                 <span asp-validation-for="Input.Email" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" /> |  | ||||||
|                 <label asp-for="Input.Password">Password</label> |  | ||||||
|                 <span asp-validation-for="Input.Password" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" /> |  | ||||||
|                 <label asp-for="Input.ConfirmPassword">Confirm Password</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" /> |  | ||||||
| } |  | ||||||
|  | @ -1,180 +0,0 @@ | ||||||
| // 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 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 turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class RegisterModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly SignInManager<IdentityUser> _signInManager; |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly IUserStore<IdentityUser> _userStore; |  | ||||||
|         private readonly IUserEmailStore<IdentityUser> _emailStore; |  | ||||||
|         private readonly ILogger<RegisterModel> _logger; |  | ||||||
|         private readonly IEmailSender _emailSender; |  | ||||||
| 
 |  | ||||||
|         public RegisterModel( |  | ||||||
|             UserManager<IdentityUser> userManager, |  | ||||||
|             IUserStore<IdentityUser> userStore, |  | ||||||
|             SignInManager<IdentityUser> signInManager, |  | ||||||
|             ILogger<RegisterModel> logger, |  | ||||||
|             IEmailSender emailSender) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _userStore = userStore; |  | ||||||
|             _emailStore = GetEmailStore(); |  | ||||||
|             _signInManager = signInManager; |  | ||||||
|             _logger = logger; |  | ||||||
|             _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 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] |  | ||||||
|             [EmailAddress] |  | ||||||
|             [Display(Name = "Email")] |  | ||||||
|             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)] |  | ||||||
|             [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.Email, CancellationToken.None); |  | ||||||
|                 await _emailStore.SetEmailAsync(user, Input.Email, 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 _emailSender.SendEmailAsync(Input.Email, "Confirm your email", |  | ||||||
|                         $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); |  | ||||||
| 
 |  | ||||||
|                     if (_userManager.Options.SignIn.RequireConfirmedAccount) |  | ||||||
|                     { |  | ||||||
|                         return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl }); |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         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 IdentityUser CreateUser() |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 return Activator.CreateInstance<IdentityUser>(); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException($"Can't create an instance of '{nameof(IdentityUser)}'. " + |  | ||||||
|                     $"Ensure that '{nameof(IdentityUser)}' is not an abstract class and has a parameterless constructor, or alternatively " + |  | ||||||
|                     $"override the register page in /Areas/Identity/Pages/Account/Register.cshtml"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private IUserEmailStore<IdentityUser> GetEmailStore() |  | ||||||
|         { |  | ||||||
|             if (!_userManager.SupportsUserEmail) |  | ||||||
|             { |  | ||||||
|                 throw new NotSupportedException("The default UI requires a user store with email support."); |  | ||||||
|             } |  | ||||||
|             return (IUserEmailStore<IdentityUser>)_userStore; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,23 +0,0 @@ | ||||||
| @page |  | ||||||
| @model RegisterConfirmationModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Register confirmation"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <h1>@ViewData["Title"]</h1> |  | ||||||
| @{ |  | ||||||
|     if (@Model.DisplayConfirmAccountLink) |  | ||||||
|     { |  | ||||||
| <p> |  | ||||||
|     This app does not currently have a real email sender registered, see <a href="https://aka.ms/aspaccountconf">these docs</a> for how to configure a real email sender. |  | ||||||
|     Normally this would be emailed: <a id="confirm-link" href="@Model.EmailConfirmationUrl">Click here to confirm your account</a> |  | ||||||
| </p> |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
| <p> |  | ||||||
|         Please check your email to confirm your account. |  | ||||||
| </p> |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
|  | @ -1,79 +0,0 @@ | ||||||
| // 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.Text; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Identity.UI.Services; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.AspNetCore.WebUtilities; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     [AllowAnonymous] |  | ||||||
|     public class RegisterConfirmationModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly IEmailSender _sender; |  | ||||||
| 
 |  | ||||||
|         public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender) |  | ||||||
|         { |  | ||||||
|             _userManager = userManager; |  | ||||||
|             _sender = sender; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <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 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> |  | ||||||
|         public bool DisplayConfirmAccountLink { 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 EmailConfirmationUrl { get; set; } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null) |  | ||||||
|         { |  | ||||||
|             if (email == null) |  | ||||||
|             { |  | ||||||
|                 return RedirectToPage("/Index"); |  | ||||||
|             } |  | ||||||
|             returnUrl = returnUrl ?? Url.Content("~/"); |  | ||||||
| 
 |  | ||||||
|             var user = await _userManager.FindByEmailAsync(email); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 return NotFound($"Unable to load user with email '{email}'."); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             Email = email; |  | ||||||
|             // Once you add a real email sender, you should remove this code that lets you confirm the account |  | ||||||
|             DisplayConfirmAccountLink = true; |  | ||||||
|             if (DisplayConfirmAccountLink) |  | ||||||
|             { |  | ||||||
|                 var userId = await _userManager.GetUserIdAsync(user); |  | ||||||
|                 var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); |  | ||||||
|                 code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); |  | ||||||
|                 EmailConfirmationUrl = Url.Page( |  | ||||||
|                     "/Account/ConfirmEmail", |  | ||||||
|                     pageHandler: null, |  | ||||||
|                     values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl }, |  | ||||||
|                     protocol: Request.Scheme); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| @page |  | ||||||
| @model ResendEmailConfirmationModel |  | ||||||
| @{ |  | ||||||
|     ViewData["Title"] = "Resend email confirmation"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| <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="All" class="text-danger" role="alert"></div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Email" class="form-control" aria-required="true" placeholder="name@example.com" /> |  | ||||||
|                 <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">Resend</button> |  | ||||||
|         </form> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,88 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Identity.UI.Services; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.AspNetCore.WebUtilities; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     [AllowAnonymous] |  | ||||||
|     public class ResendEmailConfirmationModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
|         private readonly IEmailSender _emailSender; |  | ||||||
| 
 |  | ||||||
|         public ResendEmailConfirmationModel(UserManager<IdentityUser> 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 void OnGet() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public async Task<IActionResult> OnPostAsync() |  | ||||||
|         { |  | ||||||
|             if (!ModelState.IsValid) |  | ||||||
|             { |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var user = await _userManager.FindByEmailAsync(Input.Email); |  | ||||||
|             if (user == null) |  | ||||||
|             { |  | ||||||
|                 ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email."); |  | ||||||
|                 return Page(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             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 { userId = userId, code = code }, |  | ||||||
|                 protocol: Request.Scheme); |  | ||||||
|             await _emailSender.SendEmailAsync( |  | ||||||
|                 Input.Email, |  | ||||||
|                 "Confirm your email", |  | ||||||
|                 $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); |  | ||||||
| 
 |  | ||||||
|             ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email."); |  | ||||||
|             return Page(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,37 +0,0 @@ | ||||||
| @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" role="alert"></div> |  | ||||||
|             <input asp-for="Input.Code" type="hidden" /> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" /> |  | ||||||
|                 <label asp-for="Input.Email" class="form-label"></label> |  | ||||||
|                 <span asp-validation-for="Input.Email" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="Please enter your password." /> |  | ||||||
|                 <label asp-for="Input.Password" class="form-label"></label> |  | ||||||
|                 <span asp-validation-for="Input.Password" class="text-danger"></span> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-floating mb-3"> |  | ||||||
|                 <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="Please confirm your 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">Reset</button> |  | ||||||
|         </form> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| @section Scripts { |  | ||||||
|     <partial name="_ValidationScriptsPartial" /> |  | ||||||
| } |  | ||||||
|  | @ -1,117 +0,0 @@ | ||||||
| // 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 Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using Microsoft.AspNetCore.Mvc.RazorPages; |  | ||||||
| using Microsoft.AspNetCore.WebUtilities; |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Areas.Identity.Pages.Account |  | ||||||
| { |  | ||||||
|     public class ResetPasswordModel : PageModel |  | ||||||
|     { |  | ||||||
|         private readonly UserManager<IdentityUser> _userManager; |  | ||||||
| 
 |  | ||||||
|         public ResetPasswordModel(UserManager<IdentityUser> 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(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| @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> |  | ||||||
|  | @ -1,25 +0,0 @@ | ||||||
| // 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 turf_tasker.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() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| @model string |  | ||||||
| 
 |  | ||||||
| @if (!String.IsNullOrEmpty(Model)) |  | ||||||
| { |  | ||||||
|     var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success"; |  | ||||||
|     <div class="alert alert-@statusMessageClass alert-dismissible" role="alert"> |  | ||||||
|         <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> |  | ||||||
|         @Model |  | ||||||
|     </div> |  | ||||||
| } |  | ||||||
|  | @ -1 +0,0 @@ | ||||||
| @using turf_tasker.Areas.Identity.Pages.Account |  | ||||||
|  | @ -1,2 +0,0 @@ | ||||||
| <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> |  | ||||||
| <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script> |  | ||||||
|  | @ -1,4 +0,0 @@ | ||||||
| @using Microsoft.AspNetCore.Identity |  | ||||||
| @using turf_tasker.Areas.Identity |  | ||||||
| @using turf_tasker.Areas.Identity.Pages |  | ||||||
| @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |  | ||||||
|  | @ -1,4 +0,0 @@ | ||||||
| 
 |  | ||||||
| @{ |  | ||||||
|     Layout = "/Views/Shared/_Layout.cshtml"; |  | ||||||
| } |  | ||||||
|  | @ -1,20 +1,12 @@ | ||||||
| using Microsoft.AspNetCore.Identity.EntityFrameworkCore; |  | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| using Microsoft.AspNetCore.Identity.UI; |  | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using turf_tasker.Models; | using turf_tasker.Models; | ||||||
| 
 | 
 | ||||||
| namespace turf_tasker.Data; | namespace turf_tasker.Data; | ||||||
| 
 | 
 | ||||||
| public class ApplicationDbContext : IdentityDbContext<IdentityUser> | public class ApplicationDbContext : DbContext | ||||||
| { | { | ||||||
|     private readonly DbContextOptions<ApplicationDbContext> _options; |  | ||||||
| 
 |  | ||||||
|     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) |     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) | ||||||
|         : base(options) |         : base(options) { } | ||||||
|     { |  | ||||||
|         _options = options; |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     public DbSet<LawnCareEvent> LawnCareEvents { get; set; } |     public DbSet<LawnCareEvent> LawnCareEvents { get; set; } | ||||||
|      |      | ||||||
|  |  | ||||||
							
								
								
									
										333
									
								
								Migrations/20250621230711_AddIdentitySchema.Designer.cs
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										333
									
								
								Migrations/20250621230711_AddIdentitySchema.Designer.cs
									
										
									
										generated
									
									
									
								
							|  | @ -1,333 +0,0 @@ | ||||||
| // <auto-generated /> |  | ||||||
| using System; |  | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
| using Microsoft.EntityFrameworkCore.Infrastructure; |  | ||||||
| using Microsoft.EntityFrameworkCore.Migrations; |  | ||||||
| using Microsoft.EntityFrameworkCore.Storage.ValueConversion; |  | ||||||
| using turf_tasker.Data; |  | ||||||
| 
 |  | ||||||
| #nullable disable |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Migrations |  | ||||||
| { |  | ||||||
|     [DbContext(typeof(ApplicationDbContext))] |  | ||||||
|     [Migration("20250621230711_AddIdentitySchema")] |  | ||||||
|     partial class AddIdentitySchema |  | ||||||
|     { |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         protected override void BuildTargetModel(ModelBuilder modelBuilder) |  | ||||||
|         { |  | ||||||
| #pragma warning disable 612, 618 |  | ||||||
|             modelBuilder.HasAnnotation("ProductVersion", "8.0.6"); |  | ||||||
| 
 |  | ||||||
|             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.IdentityUser", 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.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("turf_tasker.Models.LawnCareEvent", b => |  | ||||||
|                 { |  | ||||||
|                     b.Property<int>("Id") |  | ||||||
|                         .ValueGeneratedOnAdd() |  | ||||||
|                         .HasColumnType("INTEGER"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<decimal?>("AppliedAmount") |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<DateTime>("EventDate") |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<int>("EventType") |  | ||||||
|                         .HasColumnType("INTEGER"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<decimal?>("MowerHeightInches") |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<int?>("MowingPattern") |  | ||||||
|                         .HasColumnType("INTEGER"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<string>("Notes") |  | ||||||
|                         .HasMaxLength(500) |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<string>("ProblemObserved") |  | ||||||
|                         .HasMaxLength(250) |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<string>("ProductUsed") |  | ||||||
|                         .HasMaxLength(200) |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.HasKey("Id"); |  | ||||||
| 
 |  | ||||||
|                     b.ToTable("LawnCareEvents"); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             modelBuilder.Entity("turf_tasker.Models.LawnCareTip", b => |  | ||||||
|                 { |  | ||||||
|                     b.Property<int>("Id") |  | ||||||
|                         .ValueGeneratedOnAdd() |  | ||||||
|                         .HasColumnType("INTEGER"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<int>("Category") |  | ||||||
|                         .HasColumnType("INTEGER"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<string>("Content") |  | ||||||
|                         .IsRequired() |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.Property<string>("Title") |  | ||||||
|                         .IsRequired() |  | ||||||
|                         .HasMaxLength(100) |  | ||||||
|                         .HasColumnType("TEXT"); |  | ||||||
| 
 |  | ||||||
|                     b.HasKey("Id"); |  | ||||||
| 
 |  | ||||||
|                     b.ToTable("LawnCareTips"); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             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("Microsoft.AspNetCore.Identity.IdentityUser", null) |  | ||||||
|                         .WithMany() |  | ||||||
|                         .HasForeignKey("UserId") |  | ||||||
|                         .OnDelete(DeleteBehavior.Cascade) |  | ||||||
|                         .IsRequired(); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => |  | ||||||
|                 { |  | ||||||
|                     b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", 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("Microsoft.AspNetCore.Identity.IdentityUser", null) |  | ||||||
|                         .WithMany() |  | ||||||
|                         .HasForeignKey("UserId") |  | ||||||
|                         .OnDelete(DeleteBehavior.Cascade) |  | ||||||
|                         .IsRequired(); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => |  | ||||||
|                 { |  | ||||||
|                     b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) |  | ||||||
|                         .WithMany() |  | ||||||
|                         .HasForeignKey("UserId") |  | ||||||
|                         .OnDelete(DeleteBehavior.Cascade) |  | ||||||
|                         .IsRequired(); |  | ||||||
|                 }); |  | ||||||
| #pragma warning restore 612, 618 |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,222 +0,0 @@ | ||||||
| using System; |  | ||||||
| using Microsoft.EntityFrameworkCore.Migrations; |  | ||||||
| 
 |  | ||||||
| #nullable disable |  | ||||||
| 
 |  | ||||||
| namespace turf_tasker.Migrations |  | ||||||
| { |  | ||||||
|     /// <inheritdoc /> |  | ||||||
|     public partial class AddIdentitySchema : Migration |  | ||||||
|     { |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         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: "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); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         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: "AspNetRoles"); |  | ||||||
| 
 |  | ||||||
|             migrationBuilder.DropTable( |  | ||||||
|                 name: "AspNetUsers"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -15,203 +15,7 @@ namespace turf_tasker.Migrations | ||||||
|         protected override void BuildModel(ModelBuilder modelBuilder) |         protected override void BuildModel(ModelBuilder modelBuilder) | ||||||
|         { |         { | ||||||
| #pragma warning disable 612, 618 | #pragma warning disable 612, 618 | ||||||
|             modelBuilder.HasAnnotation("ProductVersion", "8.0.6"); |             modelBuilder.HasAnnotation("ProductVersion", "9.0.6"); | ||||||
| 
 |  | ||||||
|             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.IdentityUser", 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.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("turf_tasker.Models.LawnCareEvent", b => |             modelBuilder.Entity("turf_tasker.Models.LawnCareEvent", b => | ||||||
|                 { |                 { | ||||||
|  | @ -273,57 +77,6 @@ namespace turf_tasker.Migrations | ||||||
| 
 | 
 | ||||||
|                     b.ToTable("LawnCareTips"); |                     b.ToTable("LawnCareTips"); | ||||||
|                 }); |                 }); | ||||||
| 
 |  | ||||||
|             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("Microsoft.AspNetCore.Identity.IdentityUser", null) |  | ||||||
|                         .WithMany() |  | ||||||
|                         .HasForeignKey("UserId") |  | ||||||
|                         .OnDelete(DeleteBehavior.Cascade) |  | ||||||
|                         .IsRequired(); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => |  | ||||||
|                 { |  | ||||||
|                     b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", 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("Microsoft.AspNetCore.Identity.IdentityUser", null) |  | ||||||
|                         .WithMany() |  | ||||||
|                         .HasForeignKey("UserId") |  | ||||||
|                         .OnDelete(DeleteBehavior.Cascade) |  | ||||||
|                         .IsRequired(); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => |  | ||||||
|                 { |  | ||||||
|                     b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) |  | ||||||
|                         .WithMany() |  | ||||||
|                         .HasForeignKey("UserId") |  | ||||||
|                         .OnDelete(DeleteBehavior.Cascade) |  | ||||||
|                         .IsRequired(); |  | ||||||
|                 }); |  | ||||||
| #pragma warning restore 612, 618 | #pragma warning restore 612, 618 | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,22 +1,20 @@ | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using turf_tasker.Data; | using turf_tasker.Data; | ||||||
| using Microsoft.AspNetCore.Identity; |  | ||||||
| 
 | 
 | ||||||
| var builder = WebApplication.CreateBuilder(args); | var builder = WebApplication.CreateBuilder(args); | ||||||
| 
 | 
 | ||||||
|  | // Add services to the container. | ||||||
| builder.Services.AddDbContext<ApplicationDbContext>(options => | builder.Services.AddDbContext<ApplicationDbContext>(options => | ||||||
|     options.UseSqlite( |     options.UseSqlite( | ||||||
|         builder.Configuration.GetConnectionString("DefaultConnection") |         builder.Configuration.GetConnectionString("DefaultConnection") | ||||||
|     ) |     ) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) |  | ||||||
|     .AddEntityFrameworkStores<ApplicationDbContext>(); |  | ||||||
| 
 |  | ||||||
| builder.Services.AddControllersWithViews(); | builder.Services.AddControllersWithViews(); | ||||||
| 
 | 
 | ||||||
| var app = builder.Build(); | var app = builder.Build(); | ||||||
| 
 | 
 | ||||||
|  | // Configure the HTTP request pipeline. | ||||||
| if (!app.Environment.IsDevelopment()) | if (!app.Environment.IsDevelopment()) | ||||||
| { | { | ||||||
|     app.UseExceptionHandler("/Home/Error"); |     app.UseExceptionHandler("/Home/Error"); | ||||||
|  | @ -28,7 +26,6 @@ app.UseStaticFiles(); | ||||||
| 
 | 
 | ||||||
| app.UseRouting(); | app.UseRouting(); | ||||||
| 
 | 
 | ||||||
| app.UseAuthentication(); |  | ||||||
| app.UseAuthorization(); | app.UseAuthorization(); | ||||||
| 
 | 
 | ||||||
| app.MapControllerRoute( | app.MapControllerRoute( | ||||||
|  | @ -36,6 +33,4 @@ app.MapControllerRoute( | ||||||
|     pattern: "{controller=Home}/{action=Index}/{id?}" |     pattern: "{controller=Home}/{action=Index}/{id?}" | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| app.MapRazorPages(); |  | ||||||
| 
 |  | ||||||
| app.Run(); | app.Run(); | ||||||
|  | @ -33,7 +33,6 @@ | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </nav> |         </nav> | ||||||
|         <partial name="_LoginPartial" /> |  | ||||||
|     </header> |     </header> | ||||||
|     <div class="container"> |     <div class="container"> | ||||||
|         <main role="main" class="pb-3"> |         <main role="main" class="pb-3"> | ||||||
|  |  | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| @using Microsoft.AspNetCore.Identity |  | ||||||
| @inject SignInManager<IdentityUser> SignInManager |  | ||||||
| @inject UserManager<IdentityUser> UserManager |  | ||||||
| 
 |  | ||||||
| <ul class="navbar-nav"> |  | ||||||
|     @if (SignInManager.IsSignedIn(User)) |  | ||||||
|     { |  | ||||||
|         <li class="nav-item"> |  | ||||||
|             <a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @UserManager.GetUserName(User)!</a> |  | ||||||
|         </li> |  | ||||||
|         <li class="nav-item"> |  | ||||||
|             <form id="logoutForm" class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })"> |  | ||||||
|                 <button id="logout" 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" id="register" asp-area="Identity" asp-page="/Account/Register">Register</a> |  | ||||||
|         </li> |  | ||||||
|         <li class="nav-item"> |  | ||||||
|             <a class="nav-link text-dark" id="login" asp-area="Identity" asp-page="/Account/Login">Login</a> |  | ||||||
|         </li> |  | ||||||
|     } |  | ||||||
| </ul> |  | ||||||
|  | @ -7,22 +7,13 @@ | ||||||
|     </PropertyGroup> |     </PropertyGroup> | ||||||
| 
 | 
 | ||||||
|     <ItemGroup> |     <ItemGroup> | ||||||
|         <!-- Identity Packages --> |       <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.6" /> | ||||||
|         <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.6" /> |       <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.17" /> | ||||||
|         <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.6" /> |       <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.6"> | ||||||
| 
 |         <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||||||
|         <!-- Explicitly define ALL core EF Core packages to force version alignment --> |         <PrivateAssets>all</PrivateAssets> | ||||||
|         <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" /> |       </PackageReference> | ||||||
|         <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.6" /> |       <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.7" /> | ||||||
|         <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.6" /> |  | ||||||
|         <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.6" /> |  | ||||||
|         <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.6"> |  | ||||||
|             <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |  | ||||||
|             <PrivateAssets>all</PrivateAssets> |  | ||||||
|         </PackageReference> |  | ||||||
| 
 |  | ||||||
|         <!-- Scaffolding Package --> |  | ||||||
|         <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.7" /> |  | ||||||
|     </ItemGroup> |     </ItemGroup> | ||||||
| 
 | 
 | ||||||
| </Project> | </Project> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue