287 lines
14 KiB
Plaintext
287 lines
14 KiB
Plaintext
@using Microsoft.AspNetCore.Http;
|
|
@using SimpleIdServer.IdServer.Domains;
|
|
@using SimpleIdp.Resources
|
|
@using System.Security.Claims;
|
|
@model SimpleIdServer.IdServer.UI.ViewModels.ProfileViewModel
|
|
|
|
@{
|
|
ViewBag.Title = ProfileResource.title;
|
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
|
Func<string, string> getClaim = (str) =>
|
|
{
|
|
var cl = User.Claims.FirstOrDefault(c => c.Type == str);
|
|
if (cl == null) return "-";
|
|
return cl.Value;
|
|
};
|
|
var basePath = Context.Request.GetAbsoluteUriWithVirtualPath();
|
|
var returnUrl = $"{basePath}{Url.Action("Profile", "Home")}";
|
|
}
|
|
|
|
<div class="row profile gy-4">
|
|
<!-- User Information -->
|
|
<div class="col-md-3">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body info">
|
|
<div class="picture">
|
|
@Html.UserPicture(User, Model.Picture, true)
|
|
<form id="pictureForm" action="@Url.Action("UpdatePicture", "Home")" method="post">
|
|
<input type="file" id="pictureFile" name="File" style="display: none" accept="image/*" />
|
|
</form>
|
|
</div>
|
|
<ul>
|
|
<!-- Name identifier -->
|
|
<li>
|
|
<h6>@ProfileResource.subject</h6>
|
|
<span class="text-muted">@getClaim(ClaimTypes.NameIdentifier)</span>
|
|
</li>
|
|
<!-- Name -->
|
|
<li>
|
|
<h6>@ProfileResource.name</h6>
|
|
<span class="text-muted">@User.Identity.Name</span>
|
|
</li>
|
|
<!-- OTP Key -->
|
|
<li>
|
|
<h6>@ProfileResource.qrcode_otp</h6>
|
|
@if (!Model.HasOtpKey)
|
|
{
|
|
<div class="alert alert-warning">@ProfileResource.no_otp</div>
|
|
}
|
|
else
|
|
{
|
|
<div>
|
|
<img src="@Url.Action("GetOTP", "Home")" width="200px" />
|
|
</div>
|
|
}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="row gy-4">
|
|
<!-- OPENID Consents -->
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<h5>@ProfileResource.approved_apps_title</h5>
|
|
<p>@ProfileResource.approved_apps_description</p>
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>@ProfileResource.client</th>
|
|
<th>@ProfileResource.scopes</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var consent in Model.Consents.OrderBy(c => c.ClientName))
|
|
{
|
|
<tr>
|
|
<td>@Html.ClientPicture(consent.ClientUri)</td>
|
|
<td class="align-middle">@(string.IsNullOrWhiteSpace(consent.ClientName) ? '-' : consent.ClientName)</td>
|
|
<td class="align-middle">
|
|
@if(consent.ScopeNames != null && consent.ScopeNames.Any())
|
|
{
|
|
foreach(var scopeName in consent.ScopeNames)
|
|
{
|
|
<span class="badge bg-secondary">@scopeName</span>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<span>-</span>
|
|
}
|
|
</td>
|
|
<td class="align-middle">
|
|
<a href="@Url.Action("RejectConsent", "Home", new { consentId = consent.ConsentId })" class="btn btn-danger">@ProfileResource.revoke_access</a>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Pending requests -->
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<h5>@ProfileResource.pending_request_title</h5>
|
|
<p>@ProfileResource.pending_request_description</p>
|
|
@if(Model.PendingRequests != null && Model.PendingRequests.Any())
|
|
{
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>@ProfileResource.resource</th>
|
|
<th>@ProfileResource.scopes</th>
|
|
<th>@ProfileResource.requester</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var consent in Model.PendingRequests.Where(p => p.Owner == getClaim(ClaimTypes.NameIdentifier) && p.Status == UMAPendingRequestStatus.TOBECONFIRMED).OrderByDescending(u => u.CreateDateTime))
|
|
{
|
|
<tr>
|
|
<td>@(string.IsNullOrWhiteSpace(consent.ResourceName) ? '-' : consent.ResourceName)</td>
|
|
<td>
|
|
@if(consent.Scopes != null && consent.Scopes.Any())
|
|
{
|
|
<span>-</span>
|
|
}
|
|
@foreach(var scope in consent.Scopes)
|
|
{
|
|
<span class="badge bg-secondary">@scope</span>
|
|
}
|
|
</td>
|
|
<td>@consent.Requester</td>
|
|
<td>
|
|
<a href="@Url.Action("RejectUmaPendingRequest", "Home", new { ticketId = consent.TicketId})" class="btn btn-danger">@ProfileResource.revoke_access</a>
|
|
<a href="@Url.Action("ConfirmUmaPendingRequest", "Home", new { ticketId = consent.TicketId})" class="btn btn-success">@ProfileResource.accept_access</a>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
}
|
|
else
|
|
{
|
|
<i>@ProfileResource.no_pending_request</i>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- External accounts -->
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<h5>@ProfileResource.external_accounts_title</h5>
|
|
<p>@ProfileResource.external_accounts_description</p>
|
|
@if (Model.Profiles != null && Model.Profiles.Any())
|
|
{
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>@ProfileResource.account_name</th>
|
|
<th>@ProfileResource.account_login</th>
|
|
<th>@ProfileResource.created_at</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var externalAccount in Model.Profiles)
|
|
{
|
|
<tr>
|
|
<td>@externalAccount.Scheme</td>
|
|
<td>@externalAccount.Subject</td>
|
|
<td>@externalAccount.CreateDateTime.ToString("dd/M/yyyy HH:mm:ss")</td>
|
|
<td>
|
|
|
|
@using (Html.BeginForm("Unlink", "Home", FormMethod.Post))
|
|
{
|
|
@Html.AntiForgeryToken()
|
|
<input type="hidden" value="@externalAccount.Subject" name="Subject" />
|
|
<input type="hidden" value="@externalAccount.Scheme" name="Scheme" />
|
|
<button type="submit" class="btn btn-danger">@ProfileResource.unlink</button>
|
|
}
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
}
|
|
else
|
|
{
|
|
<i>@ProfileResource.no_external_accounts</i>
|
|
}
|
|
|
|
<div class="mt-2">
|
|
@foreach(var extProvider in Model.ExternalIdProviders)
|
|
{
|
|
<a class="btn btn-secondary me-1" href="@Url.Action("Link", "Home", new { scheme = extProvider.AuthenticationScheme, returnUrl = returnUrl })">
|
|
@extProvider.DisplayName
|
|
</a>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Manage credentials -->
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<h5>@ProfileResource.credentials</h5>
|
|
<div>
|
|
@if(Model.AuthenticationMethods != null && Model.AuthenticationMethods.Any(m => m.IsCredentialExists))
|
|
{
|
|
<p>@ProfileResource.update_your_credentials</p>
|
|
foreach(var authenticationMethod in Model.AuthenticationMethods.Where(m => m.IsCredentialExists))
|
|
{
|
|
<a class="btn btn-secondary me-1" href="@Url.Action("RegisterCredential", "Home", new { name = authenticationMethod.Amr, redirectUrl = returnUrl })">
|
|
@authenticationMethod.Name
|
|
</a>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<p>@ProfileResource.no_credentials_to_update</p>
|
|
}
|
|
</div>
|
|
<div>
|
|
@if(Model.AuthenticationMethods != null && Model.AuthenticationMethods.Any(m => !m.IsCredentialExists))
|
|
{
|
|
<p>@ProfileResource.enroll_credentials</p>
|
|
foreach (var authenticationMethod in Model.AuthenticationMethods.Where(m => !m.IsCredentialExists))
|
|
{
|
|
<a class="btn btn-secondary me-1" href="@Url.Action("RegisterCredential", "Home", new { name = authenticationMethod.Amr, redirectUrl = returnUrl })">
|
|
@authenticationMethod.Name
|
|
</a>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<p>@ProfileResource.no_credentials_to_create</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
<script type="text/javascript">
|
|
$(document).ready(function () {
|
|
$("#pictureFile").on("change", function (e) {
|
|
const files = e.target.files;
|
|
if (files.length != 1) return;
|
|
const action = $("#pictureForm").attr("action");
|
|
const formData = new FormData();
|
|
formData.append('file', files[0]);
|
|
$.ajax({
|
|
url: action,
|
|
type: 'POST',
|
|
data: formData,
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false,
|
|
success: function() {
|
|
var reader = new FileReader();
|
|
reader.onload = function (e) {
|
|
$('#user-picture').attr('src', e.target.result);
|
|
}
|
|
|
|
reader.readAsDataURL(files[0]);
|
|
}
|
|
});
|
|
return false;
|
|
});
|
|
$("#edit-profile").on('click', function () {
|
|
$("#pictureFile").trigger('click');
|
|
return false;
|
|
});
|
|
});
|
|
</script>
|
|
} |