Participant Registration Steps
This commit is contained in:
parent
7c54dd5a69
commit
5f9787902f
@ -5,6 +5,7 @@
|
|||||||
New = 0,
|
New = 0,
|
||||||
EmailSent = 1,
|
EmailSent = 1,
|
||||||
Registered = 2,
|
Registered = 2,
|
||||||
FaceMatch = 3
|
FaceMatch = 3,
|
||||||
|
Completed = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
public static string DefaultIfEmpty(this string s, string defaultValue) => !string.IsNullOrWhiteSpace(s) ? s : (defaultValue ?? string.Empty);
|
public static string DefaultIfEmpty(this string s, string defaultValue) => !string.IsNullOrWhiteSpace(s) ? s : (defaultValue ?? string.Empty);
|
||||||
|
|
||||||
|
public static bool IsInList(this string s, params string[] list) => list.Contains(s, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
public static string NullIfWhiteSpace(this string s) => string.IsNullOrWhiteSpace(s) ? null : s;
|
public static string NullIfWhiteSpace(this string s) => string.IsNullOrWhiteSpace(s) ? null : s;
|
||||||
|
|
||||||
public static Guid ToGuidFromBase64(this string s)
|
public static Guid ToGuidFromBase64(this string s)
|
||||||
|
@ -20,7 +20,7 @@ namespace EnotaryoPH.Web.Common.Models
|
|||||||
|
|
||||||
internal static IdentificationDocument ToEntity(this IdentificationDocumentModel model, IdentificationDocument entity)
|
internal static IdentificationDocument ToEntity(this IdentificationDocumentModel model, IdentificationDocument entity)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(model.File, nameof(model.File));
|
ArgumentNullException.ThrowIfNull(model.File);
|
||||||
|
|
||||||
entity.ExpirationDate = model.ExpirationDate.ToUTC();
|
entity.ExpirationDate = model.ExpirationDate.ToUTC();
|
||||||
entity.DateIssued = model.DateIssued.ToUTC();
|
entity.DateIssued = model.DateIssued.ToUTC();
|
||||||
|
137
EnotaryoPH/EnotaryoPH.Web/Pages/BaseTakeSelfiePageModel.cs
Normal file
137
EnotaryoPH/EnotaryoPH.Web/Pages/BaseTakeSelfiePageModel.cs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
using EnotaryoPH.Data;
|
||||||
|
using EnotaryoPH.Data.Entities;
|
||||||
|
using Exadel.Compreface.Clients.CompreFaceClient;
|
||||||
|
using Exadel.Compreface.DTOs.FaceVerificationDTOs.FaceVerification;
|
||||||
|
using Exadel.Compreface.Services;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace EnotaryoPH.Web.Pages
|
||||||
|
{
|
||||||
|
public class BaseTakeSelfiePageModel : PageModel
|
||||||
|
{
|
||||||
|
protected readonly NotaryoDBContext _notaryoDBContext;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
private readonly ICompreFaceClient _compreFaceClient;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
|
public BaseTakeSelfiePageModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService, ICompreFaceClient compreFaceClient, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_notaryoDBContext = notaryoDBContext;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
|
_compreFaceClient = compreFaceClient;
|
||||||
|
_configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task<bool> PostAsync()
|
||||||
|
{
|
||||||
|
var selfieImage = Convert.FromBase64String(SelfieBase64Image.Split(",")[1]) ?? [];
|
||||||
|
var identificationDocument = _notaryoDBContext.IdentificationDocuments.First(e => e.UserID == UserID);
|
||||||
|
var faceMatches = await VerifySelfieAsync(selfieImage, identificationDocument);
|
||||||
|
|
||||||
|
var isMatchSuccess = faceMatches.Any();
|
||||||
|
if (isMatchSuccess)
|
||||||
|
{
|
||||||
|
var signatory = _notaryoDBContext.TransactionSignatories.First(x => x.UserID == UserID);
|
||||||
|
signatory.Status = nameof(SignatoryStatus.FaceMatch);
|
||||||
|
_notaryoDBContext.Update(signatory);
|
||||||
|
|
||||||
|
var selfieEntity = CreateOrUpdateSelfie(selfieImage);
|
||||||
|
if (_notaryoDBContext.Entry(selfieEntity).State == EntityState.Detached)
|
||||||
|
{
|
||||||
|
_notaryoDBContext.Add(selfieEntity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_notaryoDBContext.Update(selfieEntity);
|
||||||
|
}
|
||||||
|
_notaryoDBContext.SaveChanges();
|
||||||
|
}
|
||||||
|
return isMatchSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Transaction _transactionEntity;
|
||||||
|
|
||||||
|
private int TransactionID
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_transactionEntity == null)
|
||||||
|
{
|
||||||
|
_transactionEntity = _notaryoDBContext.Transactions.AsNoTracking().First(x => x.Transaction_UID == Transaction_UID);
|
||||||
|
}
|
||||||
|
return _transactionEntity?.TransactionID ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private User _user;
|
||||||
|
|
||||||
|
private int UserID
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_user == null)
|
||||||
|
{
|
||||||
|
_user = _notaryoDBContext.Users.AsNoTracking().First(x => x.User_UID == _currentUserService.GetUser_UID());
|
||||||
|
}
|
||||||
|
return _user?.UserID ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<FaceMatches>> VerifySelfieAsync(byte[] selfieImage, IdentificationDocument identificationDocument)
|
||||||
|
{
|
||||||
|
var selfiePath = Path.Combine(Path.GetTempPath(), "Selfies");
|
||||||
|
if (!Directory.Exists(selfiePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(selfiePath);
|
||||||
|
}
|
||||||
|
var identificationDocumentPath = Path.Combine(selfiePath, $"{identificationDocument.IdentificationDocument_UID}.jpg");
|
||||||
|
|
||||||
|
var apiKey = _configuration.GetValue<string>("CompreFaceConfig:APIKey");
|
||||||
|
var client = _compreFaceClient.GetCompreFaceService<VerificationService>(apiKey);
|
||||||
|
var faceVerificationRequest = new FaceVerificationRequestByBytes()
|
||||||
|
{
|
||||||
|
SourceImageInBytes = selfieImage,
|
||||||
|
TargetImageInBytes = identificationDocument.File,
|
||||||
|
DetProbThreshold = 0.81m,
|
||||||
|
Limit = 1,
|
||||||
|
Status = false,
|
||||||
|
FacePlugins = []
|
||||||
|
};
|
||||||
|
var result = await client.VerifyAsync(faceVerificationRequest);
|
||||||
|
var faceMatches = result.Result.SelectMany(x => x.FaceMatches);
|
||||||
|
return faceMatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TransactionSelfie CreateOrUpdateSelfie(byte[] selfieImage)
|
||||||
|
{
|
||||||
|
TransactionSelfie selfieEntity;
|
||||||
|
if (TransactionSelfie_UID == Guid.Empty)
|
||||||
|
{
|
||||||
|
selfieEntity = new TransactionSelfie
|
||||||
|
{
|
||||||
|
CreatedOn = DateTime.UtcNow,
|
||||||
|
TransactionSelfie_UID = Guid.CreateVersion7(DateTime.UtcNow),
|
||||||
|
UserID = UserID,
|
||||||
|
TransactionID = TransactionID
|
||||||
|
};
|
||||||
|
TransactionSelfie_UID = selfieEntity.TransactionSelfie_UID.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selfieEntity = _notaryoDBContext.TransactionSelfies.FirstOrDefault(e => e.TransactionSelfie_UID == TransactionSelfie_UID);
|
||||||
|
}
|
||||||
|
selfieEntity.File = Convert.FromBase64String(SelfieBase64Image.Split(",")[1]);
|
||||||
|
return selfieEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty(SupportsGet = true)]
|
||||||
|
public Guid Transaction_UID { get; set; }
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public string SelfieBase64Image { get; set; }
|
||||||
|
|
||||||
|
[BindProperty(SupportsGet = true)]
|
||||||
|
public Guid TransactionSelfie_UID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +1,42 @@
|
|||||||
@page "{Transaction_UID:guid}"
|
@page "{Transaction_UID:guid}"
|
||||||
@model EnotaryoPH.Web.Pages.Participant.Registration.Steps.TakeSelfieModel
|
@model EnotaryoPH.Web.Pages.Participant.Registration.Steps.TakeSelfieModel
|
||||||
@{
|
@section Head {
|
||||||
|
<link href="\lib\fontawesome-free-6.7.1-web\css\all.min.css" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
#Photo {
|
||||||
|
height: 500px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
<section class="my-5">
|
<section class="my-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Registration Steps</h1>
|
|
||||||
<div class="mt-3">
|
|
||||||
<ul id="transactionwizardnav" class="nav nav-pills nav-justified d-block d-sm-flex" role="tablist">
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<a class="nav-link disabled" role="tab" data-bs-toggle="pill" href="#tab-1">
|
|
||||||
<div><span class="badge rounded-pill fs-6 me-1">STEP 1</span></div><span class="text-dark step-text">Choose Identification</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<a class="nav-link disabled active" role="tab" data-bs-toggle="pill" href="#" style="border-bottom-width: 3px;border-bottom-color: var(--bs-body-color);">
|
|
||||||
<div class="text-dark"><span class="badge rounded-pill fs-6 me-1">STEP 2</span></div><span class="text-dark step-text">Take Selfie</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="tab-content mt-3"></div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<form class="mt-3">
|
<h1>Notaryo Steps</h1>
|
||||||
<div class="ratio ratio-16x9"><iframe allowfullscreen frameborder="0" src="https://www.youtube.com/embed/d1CT5wr0I1c" width="560" height="315"></iframe></div>
|
<div class="mt-3">
|
||||||
</form>
|
@await Component.InvokeAsync("NotaryoSteps", new
|
||||||
<div class="d-flex mt-3">
|
{
|
||||||
<a class="btn btn-secondary btn-lg me-1" role="button" href="dashboard.html"><i class="fas fa-camera me-2"></i>TAKE PICTURE</a><a class="btn btn-secondary btn-lg" role="button" href="dashboard.html"><i class="fas fa-redo-alt me-2"></i>AGAIN</a>
|
NotaryoSteps = new List<NotaryoStep>() {
|
||||||
<div class="flex-grow-1"></div><button class="btn btn-primary btn-lg" type="button" data-bs-target="#modal-message" data-bs-toggle="modal">NEXT<i class="fas fa-chevron-right ms-2"></i></button>
|
new NotaryoStep { Name = "Upload Identification", Step = 1 },
|
||||||
|
new NotaryoStep { Name = "Take Selfie", Step = 2, IsActive = true }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
<div class="tab-content mt-3"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<form class="mt-3" method="post">
|
||||||
|
@await Component.InvokeAsync("TakeSelfieImage", new TakeSelfieImageModel { SelfieBase64Image = Model.SelfieBase64Image })
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
<script src="\dist\js\jfa.min.js"></script>
|
||||||
|
<script src="~/Pages/Principal/NotaryoSteps/TakeSelfie.cshtml.js" asp-append-version="true"></script>
|
||||||
|
}
|
@ -1,15 +1,38 @@
|
|||||||
|
using EnotaryoPH.Data;
|
||||||
|
using EnotaryoPH.Web.Pages.Shared.Components.TakeSelfieImage;
|
||||||
|
using Exadel.Compreface.Clients.CompreFaceClient;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
||||||
|
|
||||||
namespace EnotaryoPH.Web.Pages.Participant.Registration.Steps
|
namespace EnotaryoPH.Web.Pages.Participant.Registration.Steps
|
||||||
{
|
{
|
||||||
public class TakeSelfieModel : PageModel
|
public class TakeSelfieModel : BaseTakeSelfiePageModel
|
||||||
{
|
{
|
||||||
|
public TakeSelfieModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService, ICompreFaceClient compreFaceClient, IConfiguration configuration)
|
||||||
|
: base(notaryoDBContext, currentUserService, compreFaceClient, configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[BindProperty(SupportsGet = true)]
|
public async Task<IActionResult> OnPostAsync()
|
||||||
public Guid Transaction_UID { get; set; }
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
var isMatchSuccess = await PostAsync();
|
||||||
|
if (isMatchSuccess)
|
||||||
|
{
|
||||||
|
return Redirect($"/Participant/VideoCall/Waiting/{Transaction_UID}");
|
||||||
|
}
|
||||||
|
ModelState.AddModelError("", "Face Verification Failed");
|
||||||
|
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public TakeSelfieImageModel TakeSelfieImage { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,4 @@
|
|||||||
@page "{Transaction_UID:guid}"
|
@page "{Transaction_UID:guid}"
|
||||||
@using EnotaryoPH.Web.Pages.Shared.Components.NotaryoSteps
|
|
||||||
@using EnotaryoPH.Web.Pages.Shared.Components.UploadOrChooseIdentificationDocument
|
|
||||||
@model EnotaryoPH.Web.Pages.Participant.Registration.Steps.UploadIdentificationModel
|
@model EnotaryoPH.Web.Pages.Participant.Registration.Steps.UploadIdentificationModel
|
||||||
|
|
||||||
@section Head {
|
@section Head {
|
||||||
|
@ -18,7 +18,6 @@ namespace EnotaryoPH.Web.Pages.Participant.Registration.Steps
|
|||||||
{
|
{
|
||||||
if (UploadNewIdentification)
|
if (UploadNewIdentification)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return Page();
|
return Page();
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
@page "{Transaction_UID:guid}"
|
||||||
|
@model EnotaryoPH.Web.Pages.Participant.VideoCall.WaitingModel
|
||||||
|
@{
|
||||||
|
}
|
||||||
|
|
||||||
|
@section Head {
|
||||||
|
<link href="\lib\fontawesome-free-6.7.1-web\css\all.min.css" rel="stylesheet" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<section class="d-flex align-items-start align-items-lg-start mt-5">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Waiting for participants</h1>
|
||||||
|
<ul id="ParticipantsWaitStatus" class="list-unstyled">
|
||||||
|
<li class="my-2">
|
||||||
|
<div><i class="far fa-check-circle text-success me-1 fa-fw" data-bs-toggle="tooltip" data-bss-tooltip title="Ready"></i><span>notary1@example.com </span><span class="ms-1">- host</span></div>
|
||||||
|
</li>
|
||||||
|
<li class="my-2">
|
||||||
|
<div><i class="far fa-check-circle text-success me-1 fa-fw" data-bs-toggle="tooltip" data-bss-tooltip title="Ready"></i><span>principal1@example.com </span><span class="ms-1">- principal</span></div>
|
||||||
|
</li>
|
||||||
|
<li class="my-2">
|
||||||
|
<div><i class="far fa-check-circle text-success me-1 fa-fw" data-bs-toggle="tooltip" data-bss-tooltip title="Ready"></i><span>principal2@example.com </span><span class="ms-1">- principal</span></div>
|
||||||
|
</li>
|
||||||
|
<li class="my-2">
|
||||||
|
<div><i class="far fa-hourglass text-muted me-1 fa-fw" data-bs-toggle="tooltip" data-bss-tooltip title="Waiting..."></i><span>witness1@example.com </span><span class="ms-1">- witness</span></div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace EnotaryoPH.Web.Pages.Participant.VideoCall
|
||||||
|
{
|
||||||
|
public class WaitingModel : PageModel
|
||||||
|
{
|
||||||
|
public void OnGet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty(SupportsGet = true)]
|
||||||
|
public Guid Transaction_UID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
@page "{Transaction_UID}"
|
@page "{Transaction_UID}"
|
||||||
@using EnotaryoPH.Web.Pages.Shared.Components.NotaryoSteps
|
|
||||||
@model EnotaryoPH.Web.Pages.Principal.NotaryoSteps.ChooseNotaryModel
|
@model EnotaryoPH.Web.Pages.Principal.NotaryoSteps.ChooseNotaryModel
|
||||||
@{
|
@{
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,15 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using EnotaryoPH.Data;
|
using EnotaryoPH.Data;
|
||||||
using EnotaryoPH.Data.Entities;
|
|
||||||
using Exadel.Compreface.Clients.CompreFaceClient;
|
using Exadel.Compreface.Clients.CompreFaceClient;
|
||||||
using Exadel.Compreface.DTOs.FaceVerificationDTOs.FaceVerification;
|
|
||||||
using Exadel.Compreface.Services;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
||||||
|
|
||||||
namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
|
namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
|
||||||
{
|
{
|
||||||
public class TakeSelfieModel : PageModel
|
public class TakeSelfieModel : BaseTakeSelfiePageModel
|
||||||
{
|
{
|
||||||
private readonly NotaryoDBContext _notaryoDBContext;
|
|
||||||
private readonly ICurrentUserService _currentUserService;
|
|
||||||
private readonly ICompreFaceClient _compreFaceClient;
|
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
|
|
||||||
public TakeSelfieModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService, ICompreFaceClient compreFaceClient, IConfiguration configuration)
|
public TakeSelfieModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService, ICompreFaceClient compreFaceClient, IConfiguration configuration)
|
||||||
{
|
: base(notaryoDBContext, currentUserService, compreFaceClient, configuration)
|
||||||
_notaryoDBContext = notaryoDBContext;
|
{ }
|
||||||
_currentUserService = currentUserService;
|
|
||||||
_compreFaceClient = compreFaceClient;
|
|
||||||
_configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
@ -35,86 +21,13 @@ namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
|
|||||||
{
|
{
|
||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
|
var isMatchSuccess = await PostAsync();
|
||||||
var user = _notaryoDBContext.Users.FirstOrDefault(u => u.User_UID == _currentUserService.GetUser_UID());
|
if (isMatchSuccess)
|
||||||
|
|
||||||
TransactionSelfie selfieEntity;
|
|
||||||
if (TransactionSelfie_UID == Guid.Empty)
|
|
||||||
{
|
{
|
||||||
selfieEntity = new TransactionSelfie
|
return Redirect($"/Principal/NotaryoSteps/UploadDocument/{Transaction_UID}");
|
||||||
{
|
|
||||||
CreatedOn = DateTime.UtcNow,
|
|
||||||
TransactionSelfie_UID = Guid.CreateVersion7(DateTime.UtcNow),
|
|
||||||
UserID = user.UserID
|
|
||||||
};
|
|
||||||
TransactionSelfie_UID = selfieEntity.TransactionSelfie_UID.Value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
selfieEntity = _notaryoDBContext.TransactionSelfies.FirstOrDefault(e => e.TransactionSelfie_UID == TransactionSelfie_UID);
|
|
||||||
}
|
|
||||||
selfieEntity.File = Convert.FromBase64String(SelfieBase64Image.Split(",")[1]);
|
|
||||||
|
|
||||||
if (selfieEntity.TransactionID > 0)
|
|
||||||
{
|
|
||||||
_notaryoDBContext.TransactionSelfies.Update(selfieEntity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_notaryoDBContext.TransactionSelfies.Add(selfieEntity);
|
|
||||||
}
|
|
||||||
_notaryoDBContext.SaveChanges();
|
|
||||||
|
|
||||||
var identificationDocuments = _notaryoDBContext.IdentificationDocuments.Where(e => e.UserID == user.UserID);
|
|
||||||
var identificationDocument = identificationDocuments.First();
|
|
||||||
|
|
||||||
var selfiePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Selfies");
|
|
||||||
if (!System.IO.Directory.Exists(selfiePath))
|
|
||||||
{
|
|
||||||
System.IO.Directory.CreateDirectory(selfiePath);
|
|
||||||
}
|
|
||||||
var identificationDocumentPath = System.IO.Path.Combine(selfiePath, $"{identificationDocument.IdentificationDocument_UID}.jpg");
|
|
||||||
var selfieImagePath = System.IO.Path.Combine(selfiePath, $"{TransactionSelfie_UID}.png");
|
|
||||||
|
|
||||||
var apiKey = _configuration.GetValue<string>("CompreFaceConfig:APIKey");
|
|
||||||
var client = _compreFaceClient.GetCompreFaceService<VerificationService>(apiKey);
|
|
||||||
var faceVerificationRequest = new FaceVerificationRequestByBytes()
|
|
||||||
{
|
|
||||||
SourceImageInBytes = selfieEntity.File,
|
|
||||||
TargetImageInBytes = identificationDocument.File,
|
|
||||||
DetProbThreshold = 0.81m,
|
|
||||||
Limit = 1,
|
|
||||||
Status = false,
|
|
||||||
FacePlugins = []
|
|
||||||
};
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = await client.VerifyAsync(faceVerificationRequest);
|
|
||||||
var faceMatches = result.Result.SelectMany(x => x.FaceMatches);
|
|
||||||
|
|
||||||
if (faceMatches.Any())
|
|
||||||
{
|
|
||||||
var newTransaction = new Transaction
|
|
||||||
{
|
|
||||||
TransactionDate = DateTime.UtcNow,
|
|
||||||
CreatedOn = DateTime.UtcNow,
|
|
||||||
PrincipalID = user.UserID,
|
|
||||||
Status = nameof(TransactionState.New),
|
|
||||||
Transaction_UID = Guid.CreateVersion7(DateTime.UtcNow)
|
|
||||||
};
|
|
||||||
_notaryoDBContext.Transactions.Add(newTransaction);
|
|
||||||
selfieEntity.Transaction = newTransaction;
|
|
||||||
_notaryoDBContext.SaveChanges();
|
|
||||||
|
|
||||||
return Redirect($"/Principal/NotaryoSteps/UploadDocument/{newTransaction.Transaction_UID}");
|
|
||||||
}
|
}
|
||||||
ModelState.AddModelError("", "Face Verification Failed");
|
ModelState.AddModelError("", "Face Verification Failed");
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// capture error here
|
|
||||||
ModelState.AddModelError("", ex.Message);
|
|
||||||
}
|
|
||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,11 +69,5 @@ namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
|
|||||||
|
|
||||||
return File(selfie.File, "image/png");
|
return File(selfie.File, "image/png");
|
||||||
}
|
}
|
||||||
|
|
||||||
[BindProperty, Required]
|
|
||||||
public string SelfieBase64Image { get; set; }
|
|
||||||
|
|
||||||
[BindProperty(SupportsGet = true)]
|
|
||||||
public Guid TransactionSelfie_UID { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
const data = control_canvas.toDataURL('image/jpg');
|
const data = control_canvas.toDataURL('image/jpg');
|
||||||
control_photo.setAttribute('src', data);
|
control_photo.setAttribute('src', data);
|
||||||
|
debugger;
|
||||||
control_selfieBase64Image.value = data;
|
control_selfieBase64Image.value = data;
|
||||||
|
|
||||||
_showPhoto();
|
_showPhoto();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
@page "{Transaction_UID}"
|
@page "{Transaction_UID}"
|
||||||
@using EnotaryoPH.Web.Pages.Shared.Components.NotaryoSteps
|
@model UploadDocumentModel
|
||||||
@model EnotaryoPH.Web.Pages.Principal.NotaryoSteps.UploadDocumentModel
|
|
||||||
@{
|
@{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,79 +24,12 @@
|
|||||||
})
|
})
|
||||||
<div class="tab-content mt-3"></div>
|
<div class="tab-content mt-3"></div>
|
||||||
</div>
|
</div>
|
||||||
<form class="mt-5" enctype="multipart/form-data" method="post" id="UploadDocumentForm">
|
<form class="mt-4" id="UploadIdentificationForm" method="post" enctype="multipart/form-data">
|
||||||
<div class="row mt-3">
|
|
||||||
<div class="col-12 col-lg-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label">Document</label>
|
|
||||||
<input class="form-control" type="file" asp-for="DocumentFile" required />
|
|
||||||
@Html.ValidationMessageFor(x => x.DocumentFile)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
@await Component.InvokeAsync("UploadOrChooseIdentificationDocument", Model.Transaction_UID)
|
||||||
|
<div class="d-flex mt-3">
|
||||||
<div class="col">
|
|
||||||
<div class="mb-3"><label class="form-label">Document Type</label>
|
|
||||||
<select class="form-select" asp-for="DocumentType" asp-items="Model.DocumentTypes" required>
|
|
||||||
<option value="">Please choose an option</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
@Html.ValidationMessageFor(x => x.DocumentType)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mt-3">
|
|
||||||
<div class="col-12 col-lg-6 col-xxl-6"><label class="form-label">More than one principal?</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text">Email</span>
|
|
||||||
<input class="form-control" type="email" id="NewPrincipalEmail" />
|
|
||||||
<button class="btn btn-secondary" type="button" id="AddAdditionalPrincipalButton">ADD</button>
|
|
||||||
</div>
|
|
||||||
<div class="field-validation-error">
|
|
||||||
<span id="AdditionalPrincipalsValidation"></span>
|
|
||||||
</div>
|
|
||||||
<ul class="mt-2" id="AdditionalPrincipalsList">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-6 col-xxl-6"><label class="form-label">More than one witness?</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text">Email</span>
|
|
||||||
<input class="form-control" type="email" id="NewWitnessEmail" />
|
|
||||||
<button class="btn btn-secondary" type="button" id="AddWitnessButton">ADD</button>
|
|
||||||
</div>
|
|
||||||
<div class="field-validation-error">
|
|
||||||
<span id="WitnessesValidation"></span>
|
|
||||||
</div>
|
|
||||||
<ul class="mt-2" id="WitnessesList">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<fieldset><label class="form-label">Would you like to record the video conference?</label>
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="form-check me-3"><input id="formCheck-2" class="form-check-input" type="radio" name="IsRecorded" checked /><label class="form-check-label" for="formCheck-2">Yes, record the session</label></div>
|
|
||||||
<div class="form-check"><input id="formCheck-3" class="form-check-input" type="radio" name="IsRecorded" /><label class="form-check-label" for="formCheck-3">No, do not record the session</label></div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" asp-for="IsConfirmed" />
|
|
||||||
<label class="form-check-label" asp-for="IsConfirmed">I confirm and attest under oath that I freely and voluntarily executed the document; that I read and understood the same; and that the contents of the document are true and correct.</label>
|
|
||||||
</div>
|
|
||||||
@Html.ValidationMessageFor(x => x.IsConfirmed)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" asp-for="CurrentUserEmail" />
|
|
||||||
<input type="hidden" asp-for="ParticipantsJson" />
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="flex-grow-1"></div>
|
<div class="flex-grow-1"></div>
|
||||||
<button type="submit" class="btn btn-primary btn-lg" id="NextButton">
|
<button class="btn btn-primary btn-lg wizard__nextbutton" type="submit">NEXT<i class="fas fa-chevron-right ms-2"></i></button>
|
||||||
<span>NEXT</span>
|
|
||||||
<i class="fas fa-chevron-right ms-2"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,123 +1,66 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text.Json;
|
|
||||||
using Coravel.Queuing.Interfaces;
|
using Coravel.Queuing.Interfaces;
|
||||||
using EnotaryoPH.Data;
|
using EnotaryoPH.Data;
|
||||||
using EnotaryoPH.Data.Entities;
|
|
||||||
using EnotaryoPH.Web.Common.Jobs;
|
using EnotaryoPH.Web.Common.Jobs;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
|
||||||
namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
|
namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
|
||||||
{
|
{
|
||||||
public class UploadDocumentModel : PageModel
|
public class UploadDocumentModel : BaseIdentificationDocumentPageModel
|
||||||
{
|
{
|
||||||
private readonly ICurrentUserService _currentUserService;
|
private readonly ICurrentUserService _currentUserService;
|
||||||
private readonly NotaryoDBContext _notaryoDBContext;
|
|
||||||
private readonly IQueue _queue;
|
private readonly IQueue _queue;
|
||||||
|
|
||||||
public UploadDocumentModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService, IQueue queue)
|
public UploadDocumentModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService, IQueue queue)
|
||||||
|
: base(notaryoDBContext)
|
||||||
{
|
{
|
||||||
_notaryoDBContext = notaryoDBContext;
|
|
||||||
_currentUserService = currentUserService;
|
_currentUserService = currentUserService;
|
||||||
_queue = queue;
|
_queue = queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult OnGet(Guid transaction_UID)
|
public void OnGet()
|
||||||
{
|
{
|
||||||
var _transaction = _notaryoDBContext.Transactions
|
|
||||||
.Include(t => t.TransactionDocument)
|
|
||||||
.Include(t => t.TransactionSignatories)
|
|
||||||
.AsNoTracking().FirstOrDefault(e => e.Transaction_UID == transaction_UID);
|
|
||||||
DocumentTypes = GetDocumentTypes();
|
|
||||||
CurrentUserEmail = _currentUserService.GetEmail();
|
|
||||||
var signatories = _transaction.TransactionSignatories.Select(ts => new SignatoryViewModel
|
|
||||||
{
|
|
||||||
Email = ts.Email,
|
|
||||||
Type = ts.Type,
|
|
||||||
UID = ts.TransactionSignatory_UID.GetValueOrDefault()
|
|
||||||
}).ToList();
|
|
||||||
ParticipantsJson = JsonSerializer.Serialize(signatories);
|
|
||||||
|
|
||||||
return Page();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnPostAsync()
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
if (UploadNewIdentification)
|
||||||
{
|
{
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
DocumentTypes = GetDocumentTypes();
|
|
||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsConfirmed)
|
CreateIdentificationDocument(_currentUserService.GetUser_UID());
|
||||||
{
|
|
||||||
ModelState.AddModelError(nameof(IsConfirmed), "You must tick this box to continue.");
|
|
||||||
DocumentTypes = GetDocumentTypes();
|
|
||||||
return Page();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var transaction = _notaryoDBContext.Transactions
|
SendSignatoryInvitations();
|
||||||
.Include(t => t.TransactionSignatories)
|
|
||||||
.Include(t => t.TransactionDocument)
|
|
||||||
.FirstOrDefault(t => t.Transaction_UID == Transaction_UID);
|
|
||||||
if (transaction == null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction.Status = nameof(TransactionState.DocumentUploaded);
|
|
||||||
transaction.IsRecorded = IsVideoConferenceRecorded;
|
|
||||||
|
|
||||||
if (transaction.TransactionDocument == null)
|
|
||||||
{
|
|
||||||
transaction.TransactionDocument = new TransactionDocument
|
|
||||||
{
|
|
||||||
CreatedOn = DateTime.UtcNow,
|
|
||||||
Transaction = transaction,
|
|
||||||
TransactionDocument_UID = Guid.CreateVersion7(DateTime.UtcNow),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var stream = new MemoryStream((int)DocumentFile.Length);
|
|
||||||
DocumentFile.CopyTo(stream);
|
|
||||||
transaction.TransactionDocument.File = stream.ToArray();
|
|
||||||
transaction.TransactionDocument.Filename = DocumentFile.FileName;
|
|
||||||
transaction.TransactionDocument.DocumentType = DocumentType;
|
|
||||||
transaction.TransactionDocument.UploadedOn = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var participants = JsonSerializer.Deserialize<List<SignatoryViewModel>>(ParticipantsJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? [];
|
|
||||||
transaction.TransactionSignatories = participants.Select(p => new TransactionSignatory
|
|
||||||
{
|
|
||||||
CreatedOn = DateTime.UtcNow,
|
|
||||||
Email = p.Email,
|
|
||||||
Status = nameof(SignatoryStatus.New),
|
|
||||||
TransactionSignatory_UID = Guid.CreateVersion7(DateTime.UtcNow),
|
|
||||||
Type = p.Type,
|
|
||||||
InvitationCode = Guid.CreateVersion7(DateTime.UtcNow).ToString()
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
_notaryoDBContext.Update(transaction);
|
|
||||||
_notaryoDBContext.SaveChanges();
|
|
||||||
|
|
||||||
foreach (var signatory in transaction.TransactionSignatories)
|
|
||||||
{
|
|
||||||
_queue.QueueInvocableWithPayload<SignatoryInvitationInvocable, Guid>(signatory.TransactionSignatory_UID.GetValueOrDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Redirect($"/Principal/NotaryoSteps/ChooseNotary/{Transaction_UID}");
|
return Redirect($"/Principal/NotaryoSteps/ChooseNotary/{Transaction_UID}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SelectListItem> GetDocumentTypes()
|
private void SendSignatoryInvitations()
|
||||||
{
|
{
|
||||||
var lookupIdentificationTypes = _notaryoDBContext.LookupData.AsNoTracking().Include(e => e.LookupDataValues).FirstOrDefault(e => e.Name == "Document Types");
|
var transaction = _notaryoDBContext.Transactions
|
||||||
return lookupIdentificationTypes.LookupDataValues
|
.Include(e => e.TransactionSignatories)
|
||||||
.ConvertAll(m => new SelectListItem
|
.FirstOrDefault(e => e.Transaction_UID == Transaction_UID);
|
||||||
|
foreach (var signatory in transaction.TransactionSignatories)
|
||||||
{
|
{
|
||||||
Text = m.Title.DefaultIfEmpty(m.Value),
|
_queue.QueueInvocableWithPayload<SignatoryInvitationInvocable, Guid>(signatory.TransactionSignatory_UID.GetValueOrDefault());
|
||||||
Value = m.Value
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//private List<SelectListItem> GetDocumentTypes()
|
||||||
|
//{
|
||||||
|
// var lookupIdentificationTypes = _notaryoDBContext.LookupData.AsNoTracking().Include(e => e.LookupDataValues).FirstOrDefault(e => e.Name == "Document Types");
|
||||||
|
// return lookupIdentificationTypes.LookupDataValues
|
||||||
|
// .ConvertAll(m => new SelectListItem
|
||||||
|
// {
|
||||||
|
// Text = m.Title.DefaultIfEmpty(m.Value),
|
||||||
|
// Value = m.Value
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
|
||||||
public string CurrentUserEmail { get; private set; }
|
public string CurrentUserEmail { get; private set; }
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
@page
|
@page
|
||||||
@using EnotaryoPH.Web.Pages.Shared.Components.NotaryoSteps
|
|
||||||
|
|
||||||
@model UploadIdentificationModel
|
@model UploadIdentificationModel
|
||||||
@{
|
|
||||||
}
|
|
||||||
|
|
||||||
@section Head {
|
@section Head {
|
||||||
<link href="\lib\fontawesome-free-6.7.1-web\css\all.min.css" rel="stylesheet" />
|
<link href="\lib\fontawesome-free-6.7.1-web\css\all.min.css" rel="stylesheet" />
|
||||||
@ -24,61 +20,7 @@
|
|||||||
<div class="tab-content mt-3"></div>
|
<div class="tab-content mt-3"></div>
|
||||||
</div>
|
</div>
|
||||||
<form class="mt-4" id="UploadIdentificationForm" method="post" enctype="multipart/form-data">
|
<form class="mt-4" id="UploadIdentificationForm" method="post" enctype="multipart/form-data">
|
||||||
|
@await Component.InvokeAsync("UploadOrChooseIdentificationDocument", Model.Transaction_UID)
|
||||||
@if (Model.ExistingIdentificationDocuments.Count > 0)
|
|
||||||
{
|
|
||||||
<div class="row mt-4 mb-3">
|
|
||||||
<div class="col">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="form-check me-2"><input asp-for="UploadNewIdentification" id="UploadNewIdentificationYes" class="form-check-input" type="radio" value="true" /> <label class="form-check-label me-3" for="UploadNewIdentificationYes">Upload a new Identification Document</label></div>
|
|
||||||
<div class="form-check me-2"><input asp-for="UploadNewIdentification" id="UploadNewIdentificationNah" class="form-check-input" type="radio" value="false" /><label class="form-check-label me-3" for="UploadNewIdentificationNah">Use any of the existing Identification Documents</label></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
<input type="hidden" asp-for="UploadNewIdentification" />
|
|
||||||
}
|
|
||||||
|
|
||||||
<div id="NewIdentificationDocumentContainer">
|
|
||||||
@Html.EditorFor(m => m.NewIdentificationDocument)
|
|
||||||
</div>
|
|
||||||
@if (Model.ExistingIdentificationDocuments.Count > 0)
|
|
||||||
{
|
|
||||||
<div id="ExistingDocumentsContainer">
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col">
|
|
||||||
<h4>Existing Identification Documents</h4>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Identification Document Type</th>
|
|
||||||
<th>Expiration</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach(var id in Model.ExistingIdentificationDocuments)
|
|
||||||
{
|
|
||||||
<tr class="existingdocument__row">
|
|
||||||
<td>@id.IdentificationType</td>
|
|
||||||
<td>@id.ExpirationDate.Value.ToShortDateString()</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-danger btn-sm identificationdocument__delete__button" type="button" data-uid="@id.IdentificationDocument_UID">
|
|
||||||
<i class="fas fa-times me-1"></i>
|
|
||||||
<span class="d-none d-md-inline-block">Delete</span>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="d-flex mt-3">
|
<div class="d-flex mt-3">
|
||||||
<div class="flex-grow-1"></div>
|
<div class="flex-grow-1"></div>
|
||||||
<button class="btn btn-primary btn-lg wizard__nextbutton" type="submit">NEXT<i class="fas fa-chevron-right ms-2"></i></button>
|
<button class="btn btn-primary btn-lg wizard__nextbutton" type="submit">NEXT<i class="fas fa-chevron-right ms-2"></i></button>
|
||||||
|
@ -81,5 +81,7 @@ namespace EnotaryoPH.Web.Pages.Principal.NotaryoSteps
|
|||||||
|
|
||||||
[BindProperty]
|
[BindProperty]
|
||||||
public bool UploadNewIdentification { get; set; }
|
public bool UploadNewIdentification { get; set; }
|
||||||
|
|
||||||
|
public Guid Transaction_UID { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
@model TakeSelfieImageModel
|
||||||
|
|
||||||
|
@Html.ValidationSummary()
|
||||||
|
|
||||||
|
<div id="VideoContainer" class="bg-light">
|
||||||
|
<video id="Video" height="500" class="d-block mx-auto">Video stream not available.</video>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-none">
|
||||||
|
<canvas id="Canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="PhotoContainer" class="photo__container">
|
||||||
|
<div class="bg-light">
|
||||||
|
<img id="Photo" class="d-block mx-auto img img-fluid" alt="The screen capture will appear in this box.">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex mt-3">
|
||||||
|
<button type="button" class="btn btn-secondary btn-lg me-1" id="TakePictureButton"><i class="fas fa-camera me-2"></i>TAKE PICTURE</button>
|
||||||
|
<button type="button" class="btn btn-secondary btn-lg" id="AgainButton"><i class="fas fa-redo-alt me-2"></i>AGAIN</button>
|
||||||
|
<div class="flex-grow-1"></div>
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg" id="NextButton">NEXT<i class="fas fa-chevron-right ms-2"></i></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" asp-for="@Model.SelfieBase64Image" />
|
@ -0,0 +1,9 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace EnotaryoPH.Web.Pages.Shared.Components.TakeSelfieImage
|
||||||
|
{
|
||||||
|
public class TakeSelfieImageViewComponent : ViewComponent
|
||||||
|
{
|
||||||
|
public async Task<IViewComponentResult> InvokeAsync(TakeSelfieImageModel model) => View(model);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace EnotaryoPH.Web.Pages.Shared.Components.TakeSelfieImage
|
||||||
|
{
|
||||||
|
public class TakeSelfieImageModel
|
||||||
|
{
|
||||||
|
[BindProperty]
|
||||||
|
public string SelfieBase64Image { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
@using EnotaryoPH.Web
|
@using EnotaryoPH.Web
|
||||||
@using Microsoft.AspNetCore.Http.Extensions
|
@using Microsoft.AspNetCore.Http.Extensions
|
||||||
|
@using EnotaryoPH.Web.Pages.Shared.Components.NotaryoSteps
|
||||||
|
@using EnotaryoPH.Web.Pages.Shared.Components.UploadOrChooseIdentificationDocument
|
||||||
|
@using EnotaryoPH.Web.Pages.Shared.Components.TakeSelfieImage
|
||||||
@namespace EnotaryoPH.Web.Pages
|
@namespace EnotaryoPH.Web.Pages
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@addTagHelper *, EnotaryoPH
|
@addTagHelper *, EnotaryoPH
|
@ -24,6 +24,7 @@ namespace EnotaryoPH.Web
|
|||||||
{
|
{
|
||||||
options.Conventions.AuthorizeFolder("/Principal", "PrincipalPolicy");
|
options.Conventions.AuthorizeFolder("/Principal", "PrincipalPolicy");
|
||||||
options.Conventions.AuthorizeFolder("/Participant/Registration/Steps", "ParticipantPolicy");
|
options.Conventions.AuthorizeFolder("/Participant/Registration/Steps", "ParticipantPolicy");
|
||||||
|
options.Conventions.AuthorizeFolder("/Participant/VideoCall");
|
||||||
});
|
});
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
razorBuilder.AddRazorRuntimeCompilation();
|
razorBuilder.AddRazorRuntimeCompilation();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user