Entertainment

This commit is contained in:
Benjamin Bädorf 2022-11-27 02:47:13 +01:00
parent 766298bb44
commit 908f0ac33a
No known key found for this signature in database
GPG key ID: 4406E80E13CD656C
14 changed files with 1238 additions and 65 deletions

65
account/account.ftl Executable file
View file

@ -0,0 +1,65 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='account' bodyClass='user'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("editAccountHtmlTitle")}</h2>
</div>
<div class="col-md-2 subtitle">
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
</div>
</div>
<form action="${url.accountUrl}" class="ps-container" method="post">
<input
type="hidden"
id="stateChecker"
name="stateChecker"
value="${stateChecker}"
>
<#if !realm.registrationEmailAsUsername>
<div class="ps-form-group ${messagesPerField.printIfExists('username','has-error')}">
<label class="ps-form-group--label">${msg("username")}<#if realm.editUsernameAllowed> <span class="required">*</span></#if></label>
<input
type="text"
class="ps-input"
id="username"
name="username"
<#if !realm.editUsernameAllowed>disabled="disabled"</#if> value="${(account.username!'')}"
/>
</div>
</#if>
<div class="ps-form-group ${messagesPerField.printIfExists('email','has-error')}">
<label for="email" class="ps-form-group--label">${msg("email")} <span class="required">*</span></label>
<input type="text" class="ps-input" id="email" name="email" autofocus value="${(account.email!'')}"/>
</div>
<div class="ps-form-group ${messagesPerField.printIfExists('firstName','has-error')}">
<label for="firstName" class="ps-form-group--label">${msg("firstName")} <span class="required">*</span></label>
<input type="text" class="ps-input" id="firstName" name="firstName" value="${(account.firstName!'')}"/>
</div>
<div class="ps-form-group ${messagesPerField.printIfExists('lastName','has-error')}">
<label for="lastName" class="ps-form-group--label">${msg("lastName")} <span class="required">*</span></label>
<input type="text" class="ps-input" id="lastName" name="lastName" value="${(account.lastName!'')}"/>
</div>
<div class="ps-form-group">
<div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
<div class="">
<#if url.referrerURI??><a href="${url.referrerURI}">${kcSanitize(msg("backToApplication")?no_esc)}</a></#if>
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Save">${msg("doSave")}</button>
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Cancel">${msg("doCancel")}</button>
</div>
</div>
</div>
</form>
</@layout.mainLayout>

86
account/applications.ftl Executable file
View file

@ -0,0 +1,86 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='applications' bodyClass='applications'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("applicationsHtmlTitle")}</h2>
</div>
</div>
<form class="spot-container" action="${url.applicationsUrl}" method="post">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<input type="hidden" id="referrer" name="referrer" value="${stateChecker}">
<table class="table table-striped table-bordered">
<thead>
<tr>
<td>${msg("application")}</td>
<td>${msg("availableRoles")}</td>
<td>${msg("grantedPermissions")}</td>
<td>${msg("additionalGrants")}</td>
<td>${msg("action")}</td>
</tr>
</thead>
<tbody>
<#list applications.applications as application>
<tr>
<td>
<#if application.effectiveUrl?has_content>
<a class="ps-link" href="${application.effectiveUrl}">
</#if>
<#if application.client.name?has_content>${advancedMsg(application.client.name)}<#else>${application.client.clientId}</#if>
<#if application.effectiveUrl?has_content>
</a>
</#if>
</td>
<td>
<#list application.realmRolesAvailable as role>
<#if role.description??>${advancedMsg(role.description)}<#else>${advancedMsg(role.name)}</#if>
<#if role_has_next>, </#if>
</#list>
<#list application.resourceRolesAvailable?keys as resource>
<#if application.realmRolesAvailable?has_content>, </#if>
<#list application.resourceRolesAvailable[resource] as clientRole>
<#if clientRole.roleDescription??>${advancedMsg(clientRole.roleDescription)}<#else>${advancedMsg(clientRole.roleName)}</#if>
${msg("inResource")} <strong><#if clientRole.clientName??>${advancedMsg(clientRole.clientName)}<#else>${clientRole.clientId}</#if></strong>
<#if clientRole_has_next>, </#if>
</#list>
</#list>
</td>
<td>
<#if application.client.consentRequired>
<#list application.clientScopesGranted as claim>
${advancedMsg(claim)}<#if claim_has_next>, </#if>
</#list>
<#else>
<strong>${msg("fullAccess")}</strong>
</#if>
</td>
<td>
<#list application.additionalGrants as grant>
${advancedMsg(grant)}<#if grant_has_next>, </#if>
</#list>
</td>
<td>
<#if (application.client.consentRequired && application.clientScopesGranted?has_content) || application.additionalGrants?has_content>
<button
type='submit'
class='${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!}'
id='revoke-${application.client.clientId}'
name='clientId'
value="${application.client.id}"
>${msg("revoke")}</button>
</#if>
</td>
</tr>
</#list>
</tbody>
</table>
</form>
</@layout.mainLayout>

42
account/federatedIdentity.ftl Executable file
View file

@ -0,0 +1,42 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='social' bodyClass='social'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("federatedIdentitiesHtmlTitle")}</h2>
</div>
</div>
<div id="federated-identities">
<#list federatedIdentity.identities as identity>
<div class="row margin-bottom">
<div class="col-sm-2 col-md-2">
<label for="${identity.providerId!}" class="control-label">${identity.displayName!}</label>
</div>
<div class="col-sm-5 col-md-5">
<input disabled="true" class="form-control" value="${identity.userName!}">
</div>
<div class="col-sm-5 col-md-5">
<#if identity.connected>
<#if federatedIdentity.removeLinkPossible>
<form action="${url.socialUrl}" method="post" class="form-inline">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<input type="hidden" id="action" name="action" value="remove">
<input type="hidden" id="providerId" name="providerId" value="${identity.providerId!}">
<button id="remove-link-${identity.providerId!}" class="btn btn-default">${msg("doRemove")}</button>
</form>
</#if>
<#else>
<form action="${url.socialUrl}" method="post" class="form-inline">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<input type="hidden" id="action" name="action" value="add">
<input type="hidden" id="providerId" name="providerId" value="${identity.providerId!}">
<button id="add-link-${identity.providerId!}" class="btn btn-default">${msg("doAdd")}</button>
</form>
</#if>
</div>
</div>
</#list>
</div>
</@layout.mainLayout>

35
account/log.ftl Normal file
View file

@ -0,0 +1,35 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='log' bodyClass='log'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("accountLogHtmlTitle")}</h2>
</div>
</div>
<table class="table table-striped table-bordered">
<thead>
<tr>
<td>${msg("date")}</td>
<td>${msg("event")}</td>
<td>${msg("ip")}</td>
<td>${msg("client")}</td>
<td>${msg("details")}</td>
</tr>
</thead>
<tbody>
<#list log.events as event>
<tr>
<td>${event.date?datetime}</td>
<td>${event.event}</td>
<td>${event.ipAddress}</td>
<td>${event.client!}</td>
<td><#list event.details as detail>${detail.key} = ${detail.value} <#if detail_has_next>, </#if></#list></td>
</tr>
</#list>
</tbody>
</table>
</@layout.mainLayout>

75
account/password.ftl Executable file
View file

@ -0,0 +1,75 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='password' bodyClass='password'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("changePasswordHtmlTitle")}</h2>
</div>
<div class="col-md-2 subtitle">
<span class="subtitle">${msg("allFieldsRequired")}</span>
</div>
</div>
<form action="${url.passwordUrl}" class="ps-container" method="post">
<input
type="text"
id="username"
class="ps-input"
name="username"
value="${(account.username!'')}"
autocomplete="username"
readonly="readonly"
style="display:none;"
>
<#if password.passwordSet>
<div class="ps-form-group">
<label for="password" class="ps-form-group--label">${msg("password")}</label>
<input
type="password"
class="ps-input"
id="password"
name="password"
autofocus
autocomplete="current-password"
/>
</div>
</#if>
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<div class="ps-form-group">
<label for="password-new" class="ps-form-group--label">${msg("passwordNew")}</label>
<input
type="password"
class="ps-input"
id="password-new"
name="password-new"
autocomplete="new-password"
/>
</div>
<div class="ps-form-group">
<label for="password-confirm" class="ps-form-group--label">${msg("passwordConfirm")}</label>
<input
type="password"
class="ps-input"
id="password-confirm"
name="password-confirm"
autocomplete="new-password"
/>
</div>
<div class="ps-form-group">
<div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
<div class="">
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Save">${msg("doSave")}</button>
</div>
</div>
</div>
</form>
</@layout.mainLayout>

277
account/resource-detail.ftl Executable file
View file

@ -0,0 +1,277 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='authorization' bodyClass='authorization'; section>
<style>
.search-box,.close-icon,.search-wrapper {
position: relative;
}
.search-wrapper {
width: 500px;
margin: auto;
margin-top: 50px;
}
.search-box {
font-weight: 600;
color: white;
border: 1px solid #006e9c;
outline: 0;
border-radius: 15px;
background-color: #0085cf;
padding: 2px 5px;
}
.search-box:focus {
box-shadow: 0 0 15px 5px #b0e0ee;
border: 2px solid #bebede;
}
.close-icon {
border:1px solid transparent;
background-color: transparent;
display: inline-block;
float: right;
outline: 0;
cursor: pointer;
}
.close-icon:after {
display: block;
width: 15px;
height: 15px;
background-color: #FA9595;
z-index:1;
right: 35px;
top: 0;
bottom: 0;
margin: auto;
padding: 2px;
border-radius: 50%;
text-align: center;
color: white;
font-weight: normal;
font-size: 12px;
box-shadow: 0 0 2px #E50F0F;
cursor: pointer;
}
.search-box:not(:valid) ~ .close-icon {
display: none;
}
</style>
<script>
function removeScopeElm(elm) {
elm.parentNode.removeChild(elm);
}
function removeAllScopes(id) {
var scopesElm = document.getElementsByName('removeScope-' + id);
for (i = 0; i < scopesElm.length; i++) {
var td = scopesElm[i].parentNode.parentNode;
var tr = td.parentNode;
var tbody = tr.parentNode;
tbody.removeChild(tr);
}
}
function getChildren(parent, childId) {
var childNodes = [];
for (i = 0; i < parent.childNodes.length; i++) {
if (parent.childNodes[i].id == childId) {
childNodes.push(parent.childNodes[i]);
}
}
return childNodes;
}
</script>
<div class="row">
<div class="col-md-10">
<h2>
<a href="${url.resourceUrl}">${msg("myResources")}</a> <i class="fa fa-angle-right"></i> <#if authorization.resource.displayName??>${authorization.resource.displayName}<#else>${authorization.resource.name}</#if>
</h2>
</div>
</div>
<#if authorization.resource.iconUri??>
<img src="${authorization.resource.iconUri}">
<br/>
</#if>
<div class="row">
<div class="col-md-10">
<h3>
${msg("peopleAccessResource")}
</h3>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>${msg("user")}</th>
<th>${msg("permission")}</th>
<th>${msg("date")}</th>
<th>${msg("action")}</th>
</tr>
</thead>
<tbody>
<#if authorization.resource.shares?size != 0>
<#list authorization.resource.shares as permission>
<form action="${url.getResourceGrant(authorization.resource.id)}" name="revokeForm-${authorization.resource.id}-${permission.requester.username}" method="post">
<input type="hidden" name="action" value="revoke">
<input type="hidden" name="requester" value="${permission.requester.username}">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<tr>
<td>
<#if permission.requester.email??>${permission.requester.email}<#else>${permission.requester.username}</#if>
</td>
<td>
<#if permission.scopes?size != 0>
<#list permission.scopes as scope>
<#if scope.granted && scope.scope??>
<div class="search-box">
<#if scope.scope.displayName??>
${scope.scope.displayName}
<#else>
${scope.scope.name}
</#if>
<button class="close-icon" type="button" name="removeScope-${authorization.resource.id}-${permission.requester.username}" onclick="removeScopeElm(this.parentNode);document.forms['revokeForm-${authorization.resource.id}-${permission.requester.username}'].submit();"><i class="fa fa-times" aria-hidden="true"></i></button>
<input type="hidden" name="permission_id" value="${scope.id}"/>
</div>
<#else>
${msg("anyPermission")}
</#if>
</#list>
<#else>
Any action
</#if>
</td>
<td>
${permission.createdDate?datetime}
</td>
<td width="20%" align="middle" style="vertical-align: middle">
<a href="#" id="revoke-${authorization.resource.name}-${permission.requester.username}" onclick="removeAllScopes('${authorization.resource.id}-${permission.requester.username}');document.forms['revokeForm-${authorization.resource.id}-${permission.requester.username}'].submit();" type="submit" class="btn btn-primary">${msg("doRevoke")}</a>
</td>
</tr>
</form>
</#list>
<#else>
<tr>
<td colspan="4">${msg("resourceIsNotBeingShared")}</td>
</tr>
</#if>
</tbody>
</table>
</form>
</div>
</div>
<div class="row">
<div class="col-md-10">
<h3>
${msg("resourceManagedPolicies")}
</h3>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>${msg("description")}</th>
<th>${msg("permission")}</th>
<th>${msg("action")}</th>
</tr>
</thead>
<tbody>
<#if authorization.resource.policies?size != 0>
<#list authorization.resource.policies as permission>
<form action="${url.getResourceGrant(authorization.resource.id)}" name="revokePolicyForm-${authorization.resource.id}-${permission.id}" method="post">
<input type="hidden" name="action" value="revokePolicy">
<input type="hidden" name="permission_id" value="${permission.id}"/>
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<tr>
<td>
<#if permission.description??>
${permission.description}
</#if>
</td>
<td>
<#if permission.scopes?size != 0>
<#list permission.scopes as scope>
<div class="search-box">
<#if scope.displayName??>
${scope.displayName}
<#else>
${scope.name}
</#if>
<button class="close-icon" type="button" name="removePolicyScope-${authorization.resource.id}-${permission.id}-${scope.id}" onclick="removeScopeElm(this.parentNode);document.forms['revokePolicyForm-${authorization.resource.id}-${permission.id}'].submit();"><i class="fa fa-times" aria-hidden="true"></i></button>
<input type="hidden" name="permission_id" value="${permission.id}:${scope.id}"/>
</div>
</#list>
<#else>
${msg("anyAction")}
</#if>
</td>
<td width="20%" align="middle" style="vertical-align: middle">
<a href="#" id="revokePolicy-${authorization.resource.name}-${permission.id}" onclick="document.forms['revokePolicyForm-${authorization.resource.id}-${permission.id}']['action'].value = 'revokePolicyAll';document.forms['revokePolicyForm-${authorization.resource.id}-${permission.id}'].submit();" type="submit" class="btn btn-primary">${msg("doRevoke")}</a>
</td>
</tr>
</form>
</#list>
<#else>
<tr>
<td colspan="3">
${msg("resourceNoPermissionsGrantingAccess")}
</td>
</tr>
</#if>
</tbody>
</table>
</form>
</div>
</div>
<div class="row">
<div class="col-md-10">
<h3>
${msg("shareWithOthers")}
</h3>
</div>
</div>
<div class="row">
<div class="col-md-10">
<form action="${url.getResourceShare(authorization.resource.id)}" name="shareForm" method="post">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<div class="col-sm-3 col-md-3">
<label for="password" class="control-label">${msg("username")} or ${msg("email")} </label> <span class="required">*</span>
</div>
<div class="col-sm-8 col-md-8">
<div class="row">
<div class="col-md-12">
<input type="text" class="form-control" id="user_id" name="user_id" autofocus autocomplete="off">
</div>
<div class="col-md-12">
<br/>
<#list authorization.resource.scopes as scope>
<div id="scope" class="search-box">
<#if scope.displayName??>
${scope.displayName}
<#else>
${scope.name}
</#if>
<button class="close-icon" id="share-remove-scope-${authorization.resource.name}-${scope.name}" type="button" onclick="if (getChildren(this.parentNode.parentNode, 'scope').length > 1) {removeScopeElm(this.parentNode)}"><i class="fa fa-times" aria-hidden="true"></i></button>
<input type="hidden" name="scope_id" value="${scope.id}"/>
</div>
</#list>
</div>
<div class="col-md-12">
<br/>
<a href="#" onclick="document.forms['shareForm'].submit()" type="submit" id="share-button" class="btn btn-primary">${msg("share")}</a>
</div>
</div>
</div>
</form>
</div>
</div>
<br/>
</@layout.mainLayout>

403
account/resources.ftl Executable file
View file

@ -0,0 +1,403 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='authorization' bodyClass='authorization'; section>
<style>
.search-box,.close-icon,.search-wrapper {
position: relative;
}
.search-wrapper {
width: 500px;
margin: auto;
margin-top: 50px;
}
.search-box {
font-weight: 600;
color: white;
border: 1px solid #006e9c;
outline: 0;
border-radius: 15px;
background-color: #0085cf;
padding: 2px 5px;
}
.search-box:focus {
box-shadow: 0 0 15px 5px #b0e0ee;
border: 2px solid #bebede;
}
.close-icon {
border:1px solid transparent;
background-color: transparent;
display: inline-block;
float: right;
outline: 0;
cursor: pointer;
}
.close-icon:after {
display: block;
width: 15px;
height: 15px;
background-color: #FA9595;
z-index:1;
right: 35px;
top: 0;
bottom: 0;
margin: auto;
padding: 2px;
border-radius: 50%;
text-align: center;
color: white;
font-weight: normal;
font-size: 12px;
box-shadow: 0 0 2px #E50F0F;
cursor: pointer;
}
.search-box:not(:valid) ~ .close-icon {
display: none;
}
</style>
<script>
function showHideActions(elm) {
if (elm.style.display == 'none') {
elm.style.display = '';
} else {
elm.style.display = 'none';
}
}
function removeScopeElm(elm) {
var td = elm.parentNode;
var tr = td.parentNode;
var tbody = tr.parentNode;
td.removeChild(elm);
var childCount = td.childNodes.length - 1;
for (i = 0; i < td.childNodes.length; i++) {
if (!td.childNodes[i].tagName || td.childNodes[i].tagName.toUpperCase() != 'DIV') {
td.removeChild(td.childNodes[i]);
childCount--;
}
}
if (childCount <= 0) {
tbody.removeChild(tr);
}
}
function removeAllScopes(id) {
var scopesElm = document.getElementsByName('removeScope-' + id);
for (i = 0; i < scopesElm.length; i++) {
var td = scopesElm[i].parentNode.parentNode;
var tr = td.parentNode;
var tbody = tr.parentNode;
tbody.removeChild(tr);
}
}
function selectAllCheckBoxes(formName, elm, name) {
var shares = document.forms[formName].getElementsByTagName('input');
for (i = 0; i < shares.length; i++) {
if (shares[i].name == name) {
shares[i].checked = elm.checked;
}
}
}
</script>
<div class="row">
<div class="col-md-10">
<h2>
${msg("myResources")}
</h2>
</div>
</div>
<#if authorization.resourcesWaitingApproval?size != 0>
<div class="row">
<div class="col-md-12">
<h3>
${msg("needMyApproval")}
</h3>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>${msg("resource")}</th>
<th>${msg("requestor")}</th>
<th>${msg("permissionRequestion")}</th>
<th>${msg("action")}</th>
</tr>
</thead>
<tbody>
<#list authorization.resourcesWaitingApproval as resource>
<#list resource.permissions as permission>
<form action="${url.getResourceGrant(resource.id)}" name="approveForm-${resource.id}-${permission.requester.username}" method="post">
<input type="hidden" name="action" value="grant">
<input type="hidden" name="requester" value="${permission.requester.username}">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<tr>
<td>
<#if resource.displayName??>${resource.displayName}<#else>${resource.name}</#if>
</td>
<td>
<#if permission.requester.email??>${permission.requester.email}<#else>${permission.requester.username}</#if>
</td>
<td>
<#list permission.scopes as scope>
<#if scope.scope??>
<div class="search-box">
<#if scope.scope.displayName??>
${scope.scope.displayName}
<#else>
${scope.scope.name}
</#if>
<button class="close-icon" type="button" id="grant-remove-scope-${resource.name}-${permission.requester.username}-${scope.scope.name}" name="removeScope-${resource.id}-${permission.requester.username}" onclick="removeScopeElm(this.parentNode);document.forms['approveForm-${resource.id}-${permission.requester.username}']['action'].value = 'deny';document.forms['approveForm-${resource.id}-${permission.requester.username}'].submit();"><i class="fa fa-times" aria-hidden="true"></i></button>
<input type="hidden" name="permission_id" value="${scope.id}"/>
</div>
<#else>
${msg("anyPermission")}
</#if>
</#list>
</td>
<td width="20%" align="middle" style="vertical-align: middle">
<a href="#" id="grant-${resource.name}-${permission.requester.username}" onclick="document.forms['approveForm-${resource.id}-${permission.requester.username}']['action'].value = 'grant';document.forms['approveForm-${resource.id}-${permission.requester.username}'].submit();" type="submit" class="btn btn-primary">${msg("doApprove")}</a>
<a href="#" id="deny-${resource.name}-${permission.requester.username}" onclick="removeAllScopes('${resource.id}-${permission.requester.username}');document.forms['approveForm-${resource.id}-${permission.requester.username}']['action'].value = 'deny';document.forms['approveForm-${resource.id}-${permission.requester.username}'].submit();" type="submit" class="btn btn-danger">${msg("doDeny")}</a>
</td>
</tr>
</form>
</#list>
</#list>
</tbody>
</table>
</div>
</div>
</#if>
<div class="row">
<div class="col-md-12">
<h3>
${msg("myResourcesSub")}
</h3>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>${msg("resource")}</th>
<th>${msg("application")}</th>
<th>${msg("peopleSharingThisResource")}</th>
</tr>
</thead>
<tbody>
<#if authorization.resources?size != 0>
<#list authorization.resources as resource>
<tr>
<td>
<a id="detail-${resource.name}" href="${url.getResourceDetailUrl(resource.id)}">
<#if resource.displayName??>${resource.displayName}<#else>${resource.name}</#if>
</a>
</td>
<td>
<#if resource.resourceServer.baseUri??>
<a href="${resource.resourceServer.baseUri}">${resource.resourceServer.name}</a>
<#else>
${resource.resourceServer.name}
</#if>
</td>
<td>
<#if resource.shares?size != 0>
<a href="${url.getResourceDetailUrl(resource.id)}">${resource.shares?size} <i class="fa fa-users"></i></a>
<#else>
${msg("notBeingShared")}
</#if>
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="4">${msg("notHaveAnyResource")}</td>
</tr>
</#if>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3>
${msg("resourcesSharedWithMe")}
</h3>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form action="${url.resourceUrl}" name="shareForm" method="post">
<input type="hidden" name="action" value="cancel"/>
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="5%"><input type="checkbox" onclick="selectAllCheckBoxes('shareForm', this, 'resource_id');" <#if authorization.sharedResources?size == 0>disabled="true"</#if></td>
<th>${msg("resource")}</th>
<th>${msg("owner")}</th>
<th>${msg("application")}</th>
<th>${msg("permission")}</th>
<th>${msg("date")}</th>
</tr>
</thead>
<tbody>
<#if authorization.sharedResources?size != 0>
<#list authorization.sharedResources as resource>
<tr>
<td>
<input type="checkbox" name="resource_id" value="${resource.id}"/>
</td>
<td>
<#if resource.displayName??>${resource.displayName}<#else>${resource.name}</#if>
</td>
<td>
${resource.ownerName}
</td>
<td>
<#if resource.resourceServer.baseUri??>
<a href="${resource.resourceServer.baseUri}">${resource.resourceServer.name}</a>
<#else>
${resource.resourceServer.name}
</#if>
</td>
<td>
<#if resource.permissions?size != 0>
<ul>
<#list resource.permissions as permission>
<#list permission.scopes as scope>
<#if scope.granted && scope.scope??>
<li>
<#if scope.scope.displayName??>
${scope.scope.displayName}
<#else>
${scope.scope.name}
</#if>
</li>
<#else>
${msg("anyPermission")}
</#if>
</#list>
</#list>
</ul>
<#else>
Any action
</#if>
</td>
<td>
${resource.permissions[0].grantedDate?datetime}
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="6">${msg("noResourcesSharedWithYou")}</td>
</tr>
</#if>
</tbody>
</table>
</form>
</div>
<#if authorization.sharedResources?size != 0>
<div class="col-md-12">
<a href="#" onclick="document.forms['shareForm'].submit();" type="submit" class="btn btn-danger">${msg("doRemoveSharing")}</a>
</div>
</#if>
</div>
<#if authorization.resourcesWaitingOthersApproval?size != 0>
<br/>
<div class="row">
<div class="col-md-12">
<h3>
${msg("requestsWaitingApproval")}
</h3>
</div>
</div>
<div class="row">
<div class="col-md-12">
<i class="pficon pficon-info"></i> ${msg("havePermissionRequestsWaitingForApproval",authorization.resourcesWaitingOthersApproval?size)}
<a href="#" onclick="document.getElementById('waitingApproval').style.display=''">${msg("clickHereForDetails")}</a>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row" id="waitingApproval" style="display:none">
<div class="col-md-12">
<form action="${url.resourceUrl}" name="waitingApprovalForm" method="post">
<input type="hidden" name="action" value="cancelRequest"/>
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="5%"><input type="checkbox" onclick="selectAllCheckBoxes('waitingApprovalForm', this, 'resource_id');" <#if authorization.resourcesWaitingOthersApproval?size == 0>disabled="true"</#if></th>
<th>${msg("resource")}</th>
<th>${msg("owner")}</th>
<th>${msg("action")}</th>
<th>${msg("date")}</th>
</tr>
</thead>
<tbody>
<#list authorization.resourcesWaitingOthersApproval as resource>
<tr>
<td>
<input type="checkbox" name="resource_id" value="${resource.id}"/>
</td>
<td>
<#if resource.displayName??>${resource.displayName}<#else>${resource.name}</#if>
</td>
<td>
${resource.ownerName}
</td>
<td>
<ul>
<#list resource.permissions as permission>
<#list permission.scopes as scope>
<li>
<#if scope.scope??>
<#if scope.scope.displayName??>
${scope.scope.displayName}
<#else>
${scope.scope.name}
</#if>
<#else>
${msg("anyPermission")}
</#if>
</li>
</#list>
</#list>
</ul>
</td>
<td>
${resource.permissions[0].createdDate?datetime}
</td>
</tr>
</#list>
</tbody>
</table>
</form>
</div>
<div class="col-md-12">
<a href="#" onclick="document.forms['waitingApprovalForm'].submit();" type="submit" class="btn btn-danger">${msg("doRemoveRequest")}</a>
</div>
</div>
</div>
</div>
</#if>
</@layout.mainLayout>

44
account/sessions.ftl Executable file
View file

@ -0,0 +1,44 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='sessions' bodyClass='sessions'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("sessionsHtmlTitle")}</h2>
</div>
</div>
<table class="table table-striped table-bordered">
<thead>
<tr>
<td>${msg("ip")}</td>
<td>${msg("started")}</td>
<td>${msg("lastAccess")}</td>
<td>${msg("expires")}</td>
<td>${msg("clients")}</td>
</tr>
</thead>
<tbody>
<#list sessions.sessions as session>
<tr>
<td>${session.ipAddress}</td>
<td>${session.started?datetime}</td>
<td>${session.lastAccess?datetime}</td>
<td>${session.expires?datetime}</td>
<td>
<#list session.clients as client>
${client}<br/>
</#list>
</td>
</tr>
</#list>
</tbody>
</table>
<form action="${url.sessionsUrl}" method="post">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<button id="logout-all-sessions" class="btn btn-default">${msg("doLogOutAllSessions")}</button>
</form>
</@layout.mainLayout>

131
account/totp.ftl Executable file
View file

@ -0,0 +1,131 @@
<#import "template.ftl" as layout>
<@layout.mainLayout active='totp' bodyClass='totp'; section>
<div class="row">
<div class="col-md-10">
<h2>${msg("authenticatorTitle")}</h2>
</div>
<#if totp.otpCredentials?size == 0>
<div class="col-md-2 subtitle">
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
</div>
</#if>
</div>
<#if totp.enabled>
<table class="table table-bordered table-striped">
<thead>
<#if totp.otpCredentials?size gt 1>
<tr>
<th colspan="4">${msg("configureAuthenticators")}</th>
</tr>
<#else>
<tr>
<th colspan="3">${msg("configureAuthenticators")}</th>
</tr>
</#if>
</thead>
<tbody>
<#list totp.otpCredentials as credential>
<tr>
<td class="provider">${msg("mobile")}</td>
<#if totp.otpCredentials?size gt 1>
<td class="provider">${credential.id}</td>
</#if>
<td class="provider">${credential.userLabel!}</td>
<td class="action">
<form action="${url.totpUrl}" method="post" class="form-inline">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<input type="hidden" id="submitAction" name="submitAction" value="Delete">
<input type="hidden" id="credentialId" name="credentialId" value="${credential.id}">
<button id="remove-mobile" class="btn btn-default">
<i class="pficon pficon-delete"></i>
</button>
</form>
</td>
</tr>
</#list>
</tbody>
</table>
<#else>
<hr/>
<ol>
<li>
<p>${msg("totpStep1")}</p>
<ul>
<#list totp.supportedApplications as app>
<li>${msg(app)}</li>
</#list>
</ul>
</li>
<#if mode?? && mode = "manual">
<li>
<p>${msg("totpManualStep2")}</p>
<p><span id="kc-totp-secret-key">${totp.totpSecretEncoded}</span></p>
<p><a href="${totp.qrUrl}" id="mode-barcode">${msg("totpScanBarcode")}</a></p>
</li>
<li>
<p>${msg("totpManualStep3")}</p>
<ul>
<li id="kc-totp-type">${msg("totpType")}: ${msg("totp." + totp.policy.type)}</li>
<li id="kc-totp-algorithm">${msg("totpAlgorithm")}: ${totp.policy.getAlgorithmKey()}</li>
<li id="kc-totp-digits">${msg("totpDigits")}: ${totp.policy.digits}</li>
<#if totp.policy.type = "totp">
<li id="kc-totp-period">${msg("totpInterval")}: ${totp.policy.period}</li>
<#elseif totp.policy.type = "hotp">
<li id="kc-totp-counter">${msg("totpCounter")}: ${totp.policy.initialCounter}</li>
</#if>
</ul>
</li>
<#else>
<li>
<p>${msg("totpStep2")}</p>
<p><img src="data:image/png;base64, ${totp.totpSecretQrCode}" alt="Figure: Barcode"></p>
<p><a href="${totp.manualUrl}" id="mode-manual">${msg("totpUnableToScan")}</a></p>
</li>
</#if>
<li>
<p>${msg("totpStep3")}</p>
<p>${msg("totpStep3DeviceName")}</p>
</li>
</ol>
<hr/>
<form action="${url.totpUrl}" class="ps-container" method="post">
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
<div class="ps-form-group">
<label for="totp" class="ps-form-group--label">${msg("authenticatorCode")} <span class="required">*</span></label>
<input type="text" class="ps-input" id="totp" name="totp" autocomplete="off" autofocus>
<input type="hidden" id="totpSecret" name="totpSecret" value="${totp.totpSecret}"/>
</div>
<div class="ps-form-group" ${messagesPerField.printIfExists('userLabel',properties.kcFormGroupErrorClass!)}">
<label for="userLabel" class="ps-form-group--label">${msg("totpDeviceName")} <#if totp.otpCredentials?size gte 1><span class="required">*</span></#if></label>
<input type="text" class="ps-input" id="userLabel" name="userLabel" autocomplete="off">
</div>
<div class="ps-form-group">
<div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
<div class="">
<button type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}"
id="saveTOTPBtn" name="submitAction" value="Save">${msg("doSave")}
</button>
<button type="submit"
class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}"
id="cancelTOTPBtn" name="submitAction" value="Cancel">${msg("doCancel")}
</button>
</div>
</div>
</div>
</form>
</#if>
</@layout.mainLayout>

View file

@ -74,6 +74,8 @@ html {
.ps-form-group { .ps-form-group {
display: flex; display: flex;
flex-direction: column; } flex-direction: column; }
.ps-form-group--label {
display: flex; }
.ps-main { .ps-main {
display: flex; display: flex;
@ -100,17 +102,23 @@ html {
padding: 0; } padding: 0; }
.ps-header { .ps-header {
border-bottom: 0.5rem solid var(--foreground);
background-color: var(--background);
display: flex; display: flex;
padding: 0; padding: 0;
margin: 0; } margin: 0; }
.ps-header--title { .ps-header--title {
font-size: 1.5rem; font-size: 1.5rem;
margin: 0; } padding: 0 1rem;
margin: 0;
border-bottom: 0.5rem solid var(--foreground);
background-color: var(--background);
border-right: 0.5rem solid var(--foreground); }
.ps-header--nav { .ps-header--nav {
margin-left: auto; margin-left: auto;
display: flex; } display: flex;
border-bottom: 0.5rem solid var(--foreground);
border-left: 0.5rem solid var(--foreground);
background-color: var(--background);
padding-left: 1rem; }
.ps-header--nav-list { .ps-header--nav-list {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
@ -198,7 +206,7 @@ html {
.ps-page--section-link-icon { .ps-page--section-link-icon {
margin-left: 8px; } margin-left: 8px; }
.ps-page--section-contents { .ps-page--section-contents {
margin: 5vw; margin: 2rem;
margin-bottom: 0; margin-bottom: 0;
font-weight: 500; font-weight: 500;
line-height: 1.4; } line-height: 1.4; }

View file

@ -1,4 +1,8 @@
.ps-form-group { .ps-form-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
&--label {
display: flex;
}
} }

View file

@ -1,18 +1,24 @@
.ps-header { .ps-header {
border-bottom: 0.5rem solid var(--foreground);
background-color: var(--background);
display: flex; display: flex;
padding: 0; padding: 0;
margin: 0; margin: 0;
&--title { &--title {
font-size: 1.5rem; font-size: 1.5rem;
padding: 0 1rem;
margin: 0; margin: 0;
border-bottom: 0.5rem solid var(--foreground);
background-color: var(--background);
border-right: 0.5rem solid var(--foreground);
} }
&--nav { &--nav {
margin-left: auto; margin-left: auto;
display: flex; display: flex;
border-bottom: 0.5rem solid var(--foreground);
border-left: 0.5rem solid var(--foreground);
background-color: var(--background);
padding-left: 1rem;
} }
&--nav-list { &--nav-list {

View file

@ -93,7 +93,7 @@
} }
&--section-contents { &--section-contents {
margin: 5vw; margin: 2rem;
margin-bottom: 0; margin-bottom: 0;
font-weight: 500; font-weight: 500;
line-height: 1.4; line-height: 1.4;

View file

@ -39,7 +39,7 @@
</#if> </#if>
</head> </head>
<body class="ps-main"> <body class="ps-main ps-main_full">
<div <div
id="background" id="background"
class="ps-background ps-main--background" class="ps-background ps-main--background"
@ -59,32 +59,13 @@
</div> </div>
</div> </div>
<main class="ps-main--page ps-page"> <main class="ps-main--page ps-page">
<section class="ps-page--section"> <header class="ps-page--header ps-header">
<header class="ps-page--header">
<#if realm.internationalizationEnabled && locale.supported?size gt 1>
<div class="ps-dropdown">
<a href="#" class="ps-link ps-dropdown--trigger">${locale.current}</a>
<div class="ps-dropdown--body">
<ul class="ps-list">
<#list locale.supported as l>
<li class="ps-list--item">
<a class="ps-list--item" href="${l.url}">${l.label}</a>
</li>
</#list>
</ul>
</div>
</div>
</#if>
<#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())> <#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
<h1 class="ps-header--title"><#nested "header"></h1>
<#if displayRequiredFields> <#if displayRequiredFields>
<div class="${properties.kcContentWrapperClass!}">
<div class="${properties.kcLabelWrapperClass!} subtitle"> <div class="${properties.kcLabelWrapperClass!} subtitle">
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span> <span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
</div> </div>
<h1 class="ps-card--title"><#nested "header"></h1>
</div>
<#else>
<h1 class="ps-card--title"><#nested "header"></h1>
</#if> </#if>
<#else> <#else>
<#if displayRequiredFields> <#if displayRequiredFields>
@ -118,7 +99,22 @@
</div> </div>
</#if> </#if>
</#if> </#if>
<#if realm.internationalizationEnabled && locale.supported?size gt 1>
<div class="ps-dropdown">
<a href="#" class="ps-link ps-dropdown--trigger">${locale.current}</a>
<div class="ps-dropdown--body">
<ul class="ps-list">
<#list locale.supported as l>
<li class="ps-list--item">
<a class="ps-list--item" href="${l.url}">${l.label}</a>
</li>
</#list>
</ul>
</div>
</div>
</#if>
</header> </header>
<section class="ps-page--section ps-page--section_full">
<div class="ps-page--section-contents ps-container"> <div class="ps-page--section-contents ps-container">
<#-- App-initiated actions should not see warning messages about the need to complete the action --> <#-- App-initiated actions should not see warning messages about the need to complete the action -->
<#-- during login. --> <#-- during login. -->
@ -156,6 +152,7 @@
</div> </div>
</#if> </#if>
</div> </div>
</section>
</div> </div>
</body> </body>
</html> </html>