register user and lawyers
This commit is contained in:
parent
87ab6a874e
commit
f1b13b2877
@ -52,5 +52,8 @@ namespace EnotaryoPH.Data.Entities
|
||||
|
||||
[Column("Status")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
[ForeignKey("UserID")]
|
||||
public User User { get; set; }
|
||||
}
|
||||
}
|
@ -13,5 +13,6 @@ namespace EnotaryoPH.Data
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseNpgsql(_configuration.GetConnectionString("NotaryoDatabase"));
|
||||
|
||||
public DbSet<User>? Users { get; set; }
|
||||
public DbSet<Lawyer>? Lawyers { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace EnotaryoPH.Web.Common.Services
|
||||
{
|
||||
public interface IPasswordService
|
||||
{
|
||||
string HashPassword(string password);
|
||||
|
||||
bool VerifyHashedPassword(string hashedPassword, string providedPassword);
|
||||
}
|
||||
}
|
98
EnotaryoPH/EnotaryoPH.Web/Common/Services/PasswordService.cs
Normal file
98
EnotaryoPH/EnotaryoPH.Web/Common/Services/PasswordService.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||
|
||||
namespace EnotaryoPH.Web.Common.Services
|
||||
{
|
||||
public class PasswordService : IPasswordService
|
||||
{
|
||||
private readonly int _iterCount = 100_000;
|
||||
private readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();
|
||||
|
||||
public string HashPassword(string password) => Convert.ToBase64String(HashPasswordV3(password, _rng));
|
||||
|
||||
public bool VerifyHashedPassword(string hashedPassword, string providedPassword)
|
||||
{
|
||||
var decodedHashedPassword = Convert.FromBase64String(hashedPassword);
|
||||
return VerifyHashedPasswordV3(decodedHashedPassword, providedPassword, out var embeddedIterCount, out var prf);
|
||||
}
|
||||
|
||||
private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
|
||||
{
|
||||
// Produce a version 3 (see comment above) text hash.
|
||||
var salt = new byte[saltSize];
|
||||
rng.GetBytes(salt);
|
||||
var subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);
|
||||
|
||||
var outputBytes = new byte[13 + salt.Length + subkey.Length];
|
||||
outputBytes[0] = 0x01; // format marker
|
||||
WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
|
||||
WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
|
||||
WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
|
||||
Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
|
||||
Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
|
||||
return outputBytes;
|
||||
}
|
||||
|
||||
private static uint ReadNetworkByteOrder(byte[] buffer, int offset)
|
||||
=> ((uint)(buffer[offset + 0]) << 24)
|
||||
| ((uint)(buffer[offset + 1]) << 16)
|
||||
| ((uint)(buffer[offset + 2]) << 8)
|
||||
| buffer[offset + 3];
|
||||
|
||||
private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string password, out int iterCount, out KeyDerivationPrf prf)
|
||||
{
|
||||
iterCount = default;
|
||||
prf = default;
|
||||
|
||||
try
|
||||
{
|
||||
// Read header information
|
||||
prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1);
|
||||
iterCount = (int)ReadNetworkByteOrder(hashedPassword, 5);
|
||||
var saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9);
|
||||
|
||||
// Read the salt: must be >= 128 bits
|
||||
if (saltLength < 128 / 8)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var salt = new byte[saltLength];
|
||||
Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length);
|
||||
|
||||
// Read the subkey (the rest of the payload): must be >= 128 bits
|
||||
var subkeyLength = hashedPassword.Length - 13 - salt.Length;
|
||||
if (subkeyLength < 128 / 8)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var expectedSubkey = new byte[subkeyLength];
|
||||
Buffer.BlockCopy(hashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length);
|
||||
|
||||
// Hash the incoming password and verify it
|
||||
var actualSubkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, subkeyLength);
|
||||
return CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// This should never occur except in the case of a malformed payload, where
|
||||
// we might go off the end of the array. Regardless, a malformed payload
|
||||
// implies verification failed.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value)
|
||||
{
|
||||
buffer[offset + 0] = (byte)(value >> 24);
|
||||
buffer[offset + 1] = (byte)(value >> 16);
|
||||
buffer[offset + 2] = (byte)(value >> 8);
|
||||
buffer[offset + 3] = (byte)(value >> 0);
|
||||
}
|
||||
|
||||
private byte[] HashPasswordV3(string password, RandomNumberGenerator rng) => HashPasswordV3(password, rng,
|
||||
prf: KeyDerivationPrf.HMACSHA512,
|
||||
iterCount: _iterCount,
|
||||
saltSize: 128 / 8,
|
||||
numBytesRequested: 256 / 8);
|
||||
}
|
||||
}
|
4
EnotaryoPH/EnotaryoPH.Web/Pages/ForgotPassword.cshtml
Normal file
4
EnotaryoPH/EnotaryoPH.Web/Pages/ForgotPassword.cshtml
Normal file
@ -0,0 +1,4 @@
|
||||
@page
|
||||
@model EnotaryoPH.Web.Pages.ForgotPasswordModel
|
||||
@{
|
||||
}
|
12
EnotaryoPH/EnotaryoPH.Web/Pages/ForgotPassword.cshtml.cs
Normal file
12
EnotaryoPH/EnotaryoPH.Web/Pages/ForgotPassword.cshtml.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace EnotaryoPH.Web.Pages
|
||||
{
|
||||
public class ForgotPasswordModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
29
EnotaryoPH/EnotaryoPH.Web/Pages/Login.cshtml
Normal file
29
EnotaryoPH/EnotaryoPH.Web/Pages/Login.cshtml
Normal file
@ -0,0 +1,29 @@
|
||||
@page
|
||||
@model EnotaryoPH.Web.Pages.LoginModel
|
||||
@{
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<h1 class="my-4">Login</h1>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 col-lg-6 col-xl-5">
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col"><label class="form-label">Email</label><input id="Email" class="form-control mb-3" type="email" /></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col"><label class="form-label">Password</label><input id="Password-2" class="form-control mb-3" type="password" /></div>
|
||||
</div>
|
||||
<div class="row mt-3 mb-0">
|
||||
<div class="col">
|
||||
<button class="btn btn-primary btn-lg" type="button">Login</button>
|
||||
<a href="/Register" class="btn btn-outline-primary btn-lg ms-1" type="button">Register </a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-5 mt-2">
|
||||
<div class="col"><a href="#">Forgot password?</a></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
12
EnotaryoPH/EnotaryoPH.Web/Pages/Login.cshtml.cs
Normal file
12
EnotaryoPH/EnotaryoPH.Web/Pages/Login.cshtml.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace EnotaryoPH.Web.Pages
|
||||
{
|
||||
public class LoginModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
@page
|
||||
@model EnotaryoPH.Web.Pages.Principal.DashboardModel
|
||||
@{
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace EnotaryoPH.Web.Pages.Principal
|
||||
{
|
||||
public class DashboardModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
72
EnotaryoPH/EnotaryoPH.Web/Pages/Register.cshtml
Normal file
72
EnotaryoPH/EnotaryoPH.Web/Pages/Register.cshtml
Normal file
@ -0,0 +1,72 @@
|
||||
@page
|
||||
@model EnotaryoPH.Web.Pages.RegisterModel
|
||||
@{
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<h1 class="my-4">Sign Up</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-9 col-lg-12">
|
||||
<form method="post" asp-action="Register">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-3">
|
||||
<label class="form-label" for="Email">Email</label>
|
||||
<input id="Email" class="form-control" type="email" required asp-for="Email" />
|
||||
@Html.ValidationMessageFor(x => x.Email)
|
||||
</div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="Password">Password</label><input id="Password" class="form-control" type="password" required asp-for="Password" />
|
||||
@Html.ValidationMessageFor(x => x.Password)
|
||||
</div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="ConfirmPassword">Confirm Password</label><input id="ConfirmPassword" class="form-control" type="password" required asp-for="ConfirmPassword" />
|
||||
@Html.ValidationMessageFor(x => x.ConfirmPassword)
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="PhoneNumber">Phone number</label><input id="PhoneNumber" class="form-control mb-3" type="text" asp-for="PhoneNumber" /></div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="BirthDate">Birthdate</label><input id="BirthDate" class="form-control mb-3" type="date" required asp-for="BirthDate" /></div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col">
|
||||
<label class="form-label">Register As</label>
|
||||
<div>
|
||||
<div class="form-check form-check-inline"><input id="IsPrincipal" class="form-check-input" type="radio" name="RoleType" checked value="Principal" asp-for="RoleType" /><label class="form-check-label" for="IsPrincipal">Principal</label></div>
|
||||
<div class="form-check form-check-inline"><input id="IsNotaryPublic" class="form-check-input" type="radio" name="RoleType" value="Notary Public" asp-for="RoleType" /><label class="form-check-label" for="IsNotaryPublic">Notary Public </label></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="LawyerFields">
|
||||
<div class="row mt-4">
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="RollNumber">Roll Number</label><input id="RollNumber" class="form-control mb-3" type="text" required asp-for=RollNumber /></div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label">IBP Number</label><input id="IBPNumber" class="form-control mb-3" type="text" required asp-for="IBPNumber" /></div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="MCLEComplianceNumber">MCLE Compliance Number</label><input id="MCLEComplianceNumber" class="form-control mb-3" type="text" required asp-for="MCLEComplianceNumber" /></div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="MCLEDate">MCLE Date</label><input id="MCLEDate" class="form-control mb-3" type="date" required asp-for="MCLEDate" /></div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="PTRNumber">PTR Number</label><input id="PTRNumber" class="form-control mb-3" type="text" required asp-for="PTRNumber" /></div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label" for="PTRDate">PTR Date</label><input id="PTRDate" class="form-control mb-3" type="date" required asp-for="PTRDate" /></div>
|
||||
<div class="col"><label class="form-label" for="PTRLocation">PTR Location</label><input id="PTRLocation" class="form-control mb-3" type="text" required asp-for="PTRLocation" /></div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-lg-3"><label class="form-label">Commission Number</label><input id="CommissionNumber" class="form-control mb-3" type="text" required asp-for="CommissionNumber" /></div>
|
||||
<div class="col-12 col-lg-3"><label class="form-label">Commision Expiration</label><input id="CommisionExpiration" class="form-control mb-3" type="date" required asp-for="CommissionExpiration" /></div>
|
||||
<div class="col"><label class="form-label" for="CommissionLocation">Commission Location</label><input id="CommissionLocation" class="form-control mb-3" type="text" required asp-for="CommissionLocation" /></div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col"><label class="form-label" for="OfficeAddress">Office Address</label><input id="OfficeAddress" class="form-control mb-3" type="text" required asp-for="OfficeAddress" /></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col">
|
||||
<div class="form-check"><input id="EighteenYearsOrOlder" class="form-check-input" type="checkbox" required asp-for="IsEighteenYearsOrOlder" /><label class="form-check-label" for="EighteenYearsOrOlder">I am 18 years old or older</label></div>
|
||||
<button id="RegisterButton" class="btn btn-primary btn-lg" type="submit"><i class="fas fa-user-plus me-2"></i><span id="RegisterButtonText">Register as</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" asp-for="RoleType" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script src="~/Pages/Register.cshtml.js"></script>
|
||||
}
|
152
EnotaryoPH/EnotaryoPH.Web/Pages/Register.cshtml.cs
Normal file
152
EnotaryoPH/EnotaryoPH.Web/Pages/Register.cshtml.cs
Normal file
@ -0,0 +1,152 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using EnotaryoPH.Data;
|
||||
using EnotaryoPH.Data.Entities;
|
||||
using EnotaryoPH.Web.Common.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EnotaryoPH.Web.Pages
|
||||
{
|
||||
public class RegisterModel : PageModel
|
||||
{
|
||||
private readonly NotaryoDBContext _notaryoDBContext;
|
||||
private readonly IPasswordService _passwordService;
|
||||
|
||||
public RegisterModel(NotaryoDBContext notaryoDBContext, IPasswordService passwordService)
|
||||
{
|
||||
_notaryoDBContext = notaryoDBContext;
|
||||
_passwordService = passwordService;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
RoleType = "Principal";
|
||||
#if DEBUG
|
||||
RollNumber = "ROLL1234";
|
||||
IBPNumber = "IBP1234";
|
||||
MCLEComplianceNumber = "MCLE1234";
|
||||
MCLEDate = new DateTime(2023, 1, 15, 0, 0, 0, DateTimeKind.Utc);
|
||||
PTRDate = new DateTime(2023, 1, 15, 0, 0, 0, DateTimeKind.Utc);
|
||||
PTRLocation = "ptr location";
|
||||
PTRNumber = "PTR98723";
|
||||
CommissionExpiration = new DateTime(2023, 1, 15, 0, 0, 0, DateTimeKind.Utc);
|
||||
CommissionLocation = "COMM LOC 8732";
|
||||
CommissionNumber = "COMM NO 8392";
|
||||
OfficeAddress = "123 Fictional Road, NY, Cubao";
|
||||
|
||||
PhoneNumber = "639151220001";
|
||||
BirthDate = new DateTime(1979, 9, 10, 0, 0, 0, DateTimeKind.Utc);
|
||||
Password = "arst1234";
|
||||
ConfirmPassword = "arst1234";
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public IActionResult OnPost()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
var hasDuplicateEmail = _notaryoDBContext.Users.Any(u => EF.Functions.Like(u.Email, Email));
|
||||
if (hasDuplicateEmail)
|
||||
{
|
||||
ModelState.AddModelError(nameof(Email), "That email already exists in the database.");
|
||||
return Page();
|
||||
}
|
||||
|
||||
var newUser = new User
|
||||
{
|
||||
BirthDate = new DateTime(BirthDate.Ticks, DateTimeKind.Utc),
|
||||
Email = Email,
|
||||
PasswordHash = _passwordService.HashPassword(Password),
|
||||
PhoneNumber = PhoneNumber,
|
||||
Role = RoleType
|
||||
};
|
||||
_notaryoDBContext.Users.Add(newUser);
|
||||
|
||||
if (RoleType == "Notary Public")
|
||||
{
|
||||
var newLawyer = new Lawyer
|
||||
{
|
||||
User = newUser,
|
||||
CommissionExpiration = new DateTime(CommissionExpiration.Value.Ticks, DateTimeKind.Utc),
|
||||
CommissionLocation = CommissionLocation,
|
||||
CommissionNumber = CommissionNumber,
|
||||
IBPNumber = IBPNumber,
|
||||
MCLEComplianceNumber = MCLEComplianceNumber,
|
||||
MCLEDate = new DateTime(MCLEDate.Value.Ticks, DateTimeKind.Utc),
|
||||
OfficeAddress = OfficeAddress,
|
||||
PTRDate = new DateTime(PTRDate.Value.Ticks, DateTimeKind.Utc),
|
||||
PTRlocation = PTRLocation,
|
||||
PTRNumber = PTRNumber,
|
||||
Rollnumber = RollNumber,
|
||||
Status = "New"
|
||||
};
|
||||
_notaryoDBContext.Lawyers.Add(newLawyer);
|
||||
}
|
||||
|
||||
_notaryoDBContext.SaveChanges();
|
||||
|
||||
return RedirectToPage("/Principal/Dashboard");
|
||||
}
|
||||
|
||||
[BindProperty]
|
||||
public string Email { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string Password { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
[Compare(nameof(Password))]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime BirthDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string RoleType { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? RollNumber { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? IBPNumber { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? MCLEComplianceNumber { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime? MCLEDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? PTRNumber { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime? PTRDate { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? PTRLocation { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? CommissionNumber { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public DateTime? CommissionExpiration { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? CommissionLocation { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string? OfficeAddress { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public bool IsEighteenYearsOrOlder { get; set; }
|
||||
}
|
||||
}
|
38
EnotaryoPH/EnotaryoPH.Web/Pages/Register.cshtml.js
Normal file
38
EnotaryoPH/EnotaryoPH.Web/Pages/Register.cshtml.js
Normal file
@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
(function () {
|
||||
const
|
||||
control_isNotaryPublic = document.getElementById('IsNotaryPublic'),
|
||||
control_isPrincipal = document.getElementById('IsPrincipal'),
|
||||
control_lawyerFields = document.getElementById('LawyerFields'),
|
||||
control_registerButtonText = document.getElementById('RegisterButtonText'),
|
||||
control_roleType = document.getElementById('RoleType'),
|
||||
x = 1;
|
||||
|
||||
function _bindEvents() {
|
||||
control_isNotaryPublic.addEventListener('change', _roleTypeChanged);
|
||||
control_isPrincipal.addEventListener('change', _roleTypeChanged);
|
||||
}
|
||||
|
||||
function _roleTypeChanged(sender) {
|
||||
let roleType = sender?.target?.value ?? sender?.value ?? 'Principal';
|
||||
control_roleType.value = roleType;
|
||||
control_registerButtonText.textContent = 'Register as ' + roleType;
|
||||
if (roleType !== 'Principal') {
|
||||
control_lawyerFields.style.display = 'block';
|
||||
let requiredFields = control_lawyerFields.querySelectorAll('[required]');
|
||||
requiredFields.forEach(f => f.disabled = false);
|
||||
}
|
||||
else {
|
||||
control_lawyerFields.style.display = 'none';
|
||||
let requiredFields = control_lawyerFields.querySelectorAll('[required]');
|
||||
requiredFields.forEach(f => f.disabled = true);
|
||||
}
|
||||
}
|
||||
|
||||
function _init() {
|
||||
_roleTypeChanged(control_roleType);
|
||||
_bindEvents();
|
||||
}
|
||||
|
||||
_init();
|
||||
})();
|
@ -1,53 +1 @@
|
||||
/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
for details on configuring this project to bundle and minify static web assets. */
|
||||
|
||||
a.navbar-brand {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0077cc;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.border-top {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.box-shadow {
|
||||
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
button.accept-policy {
|
||||
font-size: 1rem;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
line-height: 60px;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: red;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using EnotaryoPH.Data;
|
||||
using EnotaryoPH.Web.Common.Services;
|
||||
|
||||
namespace EnotaryoPH.Web
|
||||
{
|
||||
@ -10,8 +11,8 @@ namespace EnotaryoPH.Web
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorPages();
|
||||
|
||||
builder.Services.AddDbContext<NotaryoDBContext>();
|
||||
builder.Services.AddTransient<IPasswordService, PasswordService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
@ -116,3 +116,14 @@ a span.sidemenu__menuitem__text {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.field-validation-error {
|
||||
color: var(--bs-danger);
|
||||
font-size: small;
|
||||
margin-bottom: 15px;
|
||||
display: block;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.input-validation-error {
|
||||
border: solid 1px var(--bs-danger)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user