dev #12
@ -1,9 +1,57 @@
|
||||
@page
|
||||
@model WebApp.Pages.LoginModel
|
||||
<form method="post">
|
||||
<input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus name="email">
|
||||
@{
|
||||
ViewData["Title"] = "Log In";
|
||||
}
|
||||
<section class="vh-100">
|
||||
<style>
|
||||
.bg-image-vertical {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
background-size: auto 100%;
|
||||
}
|
||||
|
||||
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required name="password">
|
||||
@@media (min-width: 1025px) {
|
||||
.h-custom-2 {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 text-black">
|
||||
<div class="d-flex align-items-center h-custom-2 px-5 ms-xl-4 mt-5 pt-5 pt-xl-0 mt-xl-n5">
|
||||
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
|
||||
</form>
|
||||
<form style="width: 23rem;" method="post">
|
||||
|
||||
<h3 class="fw-normal mb-3 pb-3" style="letter-spacing: 1px;">Log in</h3>
|
||||
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input type="email" id="email" class="form-control form-control-lg" name="email" />
|
||||
<label class="form-label" for="email">Email address</label>
|
||||
</div>
|
||||
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input type="password" id="password" class="form-control form-control-lg" name="password" />
|
||||
<label class="form-label" for="password">Password</label>
|
||||
</div>
|
||||
|
||||
<div class="pt-1 mb-4">
|
||||
<button data-mdb-button-init data-mdb-ripple-init class="btn btn-info btn-lg btn-block" type="submit">Login</button>
|
||||
</div>
|
||||
|
||||
<p>Don't have an account? <a asp-page="/SignUp" class="link-info">Register here</a></p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-sm-6 px-0 d-none d-sm-block">
|
||||
<img src="~/background-login.jpg"
|
||||
alt="Login image" class="w-100 vh-100" style="object-fit: cover; object-position: left;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
@ -11,18 +11,18 @@ namespace WebApp.Pages
|
||||
{
|
||||
}
|
||||
|
||||
public void OnPostAsync(string email, string password)
|
||||
public IActionResult OnPostAsync(string email, string password)
|
||||
{
|
||||
var response = APIClient.PostRequest("user/login", new { email, password });
|
||||
|
||||
if (response is null || response is not string)
|
||||
{
|
||||
return;
|
||||
throw new Exception("Something wrong LOL!");
|
||||
}
|
||||
string token = (string)JsonConvert.DeserializeObject((string)response);
|
||||
// Ñîõðàíÿåì â êóêèñ òîêåí
|
||||
Response.Cookies.Append("21gunsthebest", token);
|
||||
Redirect("/");
|
||||
|
||||
this.SetJWT((string)response);
|
||||
|
||||
return RedirectToPage("Index");
|
||||
}
|
||||
}
|
||||
}
|
30
WebApp/Pages/PageModelExtension.cs
Normal file
30
WebApp/Pages/PageModelExtension.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace WebApp.Pages
|
||||
{
|
||||
public static class PageModelExtension
|
||||
{
|
||||
public static string? GetUserId(this PageModel pageModel)
|
||||
{
|
||||
if (pageModel.User.Identity.IsAuthenticated)
|
||||
{
|
||||
var userIdClaim = pageModel.User.Claims.FirstOrDefault(c => c.Type == "userId");
|
||||
return userIdClaim?.Value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void SetJWT(this PageModel pageModel, string jwt)
|
||||
{
|
||||
string token = (string)JsonConvert.DeserializeObject(jwt);
|
||||
// Сохраняем в кукис токен
|
||||
pageModel.Response.Cookies.Append("21gunsthebest", token);
|
||||
}
|
||||
|
||||
public static void DeleteJWT(this PageModel pageModel)
|
||||
{
|
||||
pageModel.Response.Cookies.Delete("21gunsthebest");
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - WebApp</title>
|
||||
<title>@ViewData["Title"] - 21 GUNS</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/WebApp.styles.css" asp-append-version="true" />
|
||||
@ -12,7 +12,7 @@
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">WebApp</a>
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">21 GUNS</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
@ -25,6 +25,18 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
</li>
|
||||
@if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/User/Index">Profile</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Login">Login</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -38,7 +50,7 @@
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
© 2024 - WebApp - <a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
© 2024 - 21 GUNS - <a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
93
WebApp/Pages/SignUp.cshtml
Normal file
93
WebApp/Pages/SignUp.cshtml
Normal file
@ -0,0 +1,93 @@
|
||||
@page
|
||||
@model WebApp.Pages.SignUpModel
|
||||
@{
|
||||
ViewData["Title"] = "Sign Up";
|
||||
}
|
||||
|
||||
<!-- Section: Design Block -->
|
||||
<section class="overflow-hidden">
|
||||
<style>
|
||||
.bg-glass {
|
||||
background-color: hsla(0, 0%, 100%, 0.9) !important;
|
||||
backdrop-filter: saturate(200%) blur(25px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container px-4 py-5 px-md-5 text-center text-lg-start my-5">
|
||||
<div class="row gx-lg-5 align-items-center mb-5">
|
||||
<div class="col-lg-6 mb-5 mb-lg-0" style="z-index: 10">
|
||||
<h1 class="my-5 display-5 fw-bold ls-tight" style="color: #373A40">
|
||||
Time to buy some... guns!*<br />
|
||||
<span style="color: #DC5F00">In the store** of death*** and despair****</span>
|
||||
</h1>
|
||||
<div class="mb-4 opacity-70 text-body-emphasis" style="color: #686D76">
|
||||
<p>
|
||||
We would like to draw your attention to the fact that our company does not sell products to anyone under the age of 18. All of our products are intended for adult audiences only. We also do not ship to countries where our products are prohibited or restricted by law. Please make sure you meet all the necessary requirements before placing your order. We appreciate your understanding and co-operation in this matter.
|
||||
<div style="font-size: 6px">
|
||||
*toy guns,
|
||||
**21 guns,
|
||||
***a metaphor for death of the happiness of buying our merchandise,
|
||||
****a metaphor for despair over the consumer's failure to find this shop previously
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 mb-5 mb-lg-0 position-relative">
|
||||
|
||||
<div class="card bg-glass">
|
||||
<div class="card-body px-4 py-5 px-md-5">
|
||||
<form method="post">
|
||||
<!-- 2 column grid layout with text inputs for the first and last names -->
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div data-mdb-input-init class="form-outline">
|
||||
<input asp-for="UserModel.FirstName" type="text" id="firstname" class="form-control" />
|
||||
<label class="form-label" for="firstname">First name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div data-mdb-input-init class="form-outline">
|
||||
<input asp-for="UserModel.SecondName" type="text" id="lastname" class="form-control" />
|
||||
<label class="form-label" for="lastname">Last name</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email input -->
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input asp-for="UserModel.Email" type="email" id="email" class="form-control" />
|
||||
<label class="form-label" for="email">Email address</label>
|
||||
</div>
|
||||
|
||||
<!-- Password input -->
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input asp-for="UserModel.Password" type="password" id="password" class="form-control" />
|
||||
<label class="form-label" for="password">Password</label>
|
||||
</div>
|
||||
|
||||
<!-- Checkbox -->
|
||||
<div class="form-check d-flex justify-content-center mb-4">
|
||||
<input class="form-check-input me-2" type="checkbox" value="" id="confirming" />
|
||||
<label class="form-check-label" for="confirming">
|
||||
I confirm that I am 18 years of age and have read the Privacy Policy and Terms of Agreement
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Submit button -->
|
||||
<button type="submit" data-mdb-button-init data-mdb-ripple-init class="btn btn-primary btn-block mb-4">
|
||||
Sign up
|
||||
</button>
|
||||
<div>
|
||||
<p class="mb-0">
|
||||
Already have an account? <a class="fw-bold" asp-area="" asp-page="/Login">Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Section: Design Block -->
|
38
WebApp/Pages/SignUp.cshtml.cs
Normal file
38
WebApp/Pages/SignUp.cshtml.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using Contracts.BindingModels;
|
||||
using Contracts.ViewModels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using WebApp.Helpers;
|
||||
|
||||
namespace WebApp.Pages
|
||||
{
|
||||
public class SignUpModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public UserBindingModel UserModel { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
|
||||
public IActionResult OnPostAsync()
|
||||
{
|
||||
var userRole = APIClient.GetRequest<RoleViewModel>($"role/get?name={Roles.User}");
|
||||
if (userRole is null)
|
||||
{
|
||||
throw new Exception("User role is not found");
|
||||
}
|
||||
UserModel.Role = new() { Id = userRole.Id };
|
||||
var response = APIClient.PostRequest("user/registration", UserModel);
|
||||
|
||||
if (response is null || response is not string)
|
||||
{
|
||||
throw new Exception("Something wrong LOL!");
|
||||
}
|
||||
|
||||
this.SetJWT((string)response);
|
||||
|
||||
return RedirectToPage("Index");
|
||||
}
|
||||
}
|
||||
}
|
23
WebApp/Pages/User/Index.cshtml
Normal file
23
WebApp/Pages/User/Index.cshtml
Normal file
@ -0,0 +1,23 @@
|
||||
@page
|
||||
@model WebApp.Pages.User.IndexModel
|
||||
@{
|
||||
ViewData["Title"] = "User page";
|
||||
}
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<h1 class="text-center">@Model.UserModel.FirstName @Model.UserModel.SecondName</h1>
|
||||
<p class="text-center">@Model.UserModel.Email</p>
|
||||
<hr>
|
||||
<div class="mt-3">
|
||||
<a class="btn btn-primary" asp-page="/User/Settings">Settings</a>
|
||||
</div>
|
||||
<form asp-page-handler="SignOut" method="post">
|
||||
<div class="mt-3">
|
||||
<button class="btn btn-danger">Sign out</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
32
WebApp/Pages/User/Index.cshtml.cs
Normal file
32
WebApp/Pages/User/Index.cshtml.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using Contracts.BindingModels;
|
||||
using Contracts.ViewModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using WebApp.Helpers;
|
||||
|
||||
namespace WebApp.Pages.User
|
||||
{
|
||||
[Authorize(Roles = Roles.User)]
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
public UserViewModel UserModel { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
var id = this.GetUserId();
|
||||
if (id is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UserModel = APIClient.GetRequest<UserViewModel>($"user/get?id={id}");
|
||||
}
|
||||
|
||||
public IActionResult OnPostSignOut()
|
||||
{
|
||||
this.DeleteJWT();
|
||||
return RedirectToPage("../Index");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +1,54 @@
|
||||
@page
|
||||
@model WebApp.Pages.User.SettingsModel
|
||||
|
||||
<div class="card bg-glass">
|
||||
<div class="card-body px-4 py-5 px-md-5">
|
||||
<form method="post">
|
||||
<!-- 2 column grid layout with text inputs for the first and last names -->
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div data-mdb-input-init class="form-outline">
|
||||
<input asp-for="UserModel.FirstName" type="text" id="firstname" class="form-control" />
|
||||
<label class="form-label" for="firstname">First name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div data-mdb-input-init class="form-outline">
|
||||
<input asp-for="UserModel.SecondName" type="text" id="lastname" class="form-control" />
|
||||
<label class="form-label" for="lastname">Last name</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email input -->
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input asp-for="UserModel.Email" type="email" id="email" class="form-control" />
|
||||
<label class="form-label" for="email">Email address</label>
|
||||
</div>
|
||||
|
||||
<!-- Password input -->
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input asp-for="UserModel.Password" type="password" id="password" class="form-control" />
|
||||
<label class="form-label" for="password">Password</label>
|
||||
</div>
|
||||
|
||||
<!-- Birthday input -->
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input asp-for="UserModel.Birthday" type="date" id="birthday" class="form-control" />
|
||||
<label class="form-label" for="birthday">Birthday</label>
|
||||
</div>
|
||||
|
||||
<!-- Hidden inputs -->
|
||||
<input type="hidden" asp-for="UserModel.Id" />
|
||||
<input type="hidden" asp-for="UserModel.Role.Id" />
|
||||
|
||||
<!-- Submit button -->
|
||||
<button type="submit" data-mdb-button-init data-mdb-ripple-init class="btn btn-primary btn-block mb-4">
|
||||
Save settings
|
||||
</button>
|
||||
</form>
|
||||
<form asp-page-handler="DeleteProfile" method="post">
|
||||
<button class="btn btn-danger btn-block mb-4">Delete this account permanently</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -1,3 +1,6 @@
|
||||
using Contracts.BindingModels;
|
||||
using Contracts.Converters;
|
||||
using Contracts.ViewModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
@ -5,11 +8,58 @@ using WebApp.Helpers;
|
||||
|
||||
namespace WebApp.Pages.User
|
||||
{
|
||||
[Authorize(Roles = Roles.Admin + Roles.Worker)]
|
||||
[Authorize(Roles = Roles.User)]
|
||||
public class SettingsModel : PageModel
|
||||
{
|
||||
[BindProperty]
|
||||
public UserBindingModel UserModel { get; set; }
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
var id = this.GetUserId();
|
||||
if (id is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var userView = APIClient.GetRequest<UserViewModel>($"user/get?id={id}");
|
||||
if (userView is null)
|
||||
{
|
||||
throw new Exception("User is not found.");
|
||||
}
|
||||
|
||||
UserModel = UserConverter.ToBinding(userView);
|
||||
}
|
||||
|
||||
public IActionResult OnPostDeleteProfile()
|
||||
{
|
||||
var id = this.GetUserId();
|
||||
if (id is null)
|
||||
{
|
||||
throw new Exception("User not found!");
|
||||
}
|
||||
|
||||
var response = APIClient.DeleteRequest($"user/delete?id={id}");
|
||||
if (response is null)
|
||||
{
|
||||
throw new Exception("Something wrong LOL!");
|
||||
}
|
||||
|
||||
this.DeleteJWT();
|
||||
|
||||
return RedirectToPage("../Index");
|
||||
}
|
||||
|
||||
public IActionResult OnPostAsync()
|
||||
{
|
||||
var response = APIClient.PatchRequest("user/update", UserModel);
|
||||
|
||||
if (response is null)
|
||||
{
|
||||
throw new Exception("Something wrong LOL!");
|
||||
}
|
||||
|
||||
return RedirectToPage("Index");
|
||||
}
|
||||
}
|
||||
}
|
BIN
WebApp/wwwroot/background-login.jpg
Normal file
BIN
WebApp/wwwroot/background-login.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
Loading…
Reference in New Issue
Block a user