085b95a0ed083eaf4fafa4c131a0496664d37f93
4 * This renders the administrative view for an account,
5 * allowing for adding profile URIs, custom scope bundles,
6 * and management of issued tokens.
9 const th
= require('./template-helper');
12 function renderProfileLI(profile
) {
13 return `\t<li><a class="uri" name="${profile}">${profile}</a></li>`;
17 function renderProfileScopeIndicator(profile
, scope
, selected
) {
18 const checked
= selected
? ' checked' : '';
20 \t\t\t<input type="checkbox" id="${profile}-${scope}" name="scopes-${profile}" value="${scope}"${checked}>
24 function renderScopeRow(scope
, details
, profiles
) {
25 return `\t<tr class="scope">
26 ${(profiles || []).map((profile) => renderProfileScopeIndicator(profile, scope, details.profiles.includes(profile))).join('\n')}
27 \t\t<th scope="row"><label>${scope}<label></th>
28 \t\t<td class="description">${details.description}</td>
29 \t\t<td>${details.application}</td>
30 \t\t<td class="scope-actions">` +
31 (details
.isManuallyAdded
? `
32 \t\t\t<button name="action" value="delete-scope-${encodeURIComponent(scope)}">Delete</button>
39 function renderProfileHeader(profile
) {
40 return `<th class="vertical uri">
46 function scopeIndexTable(scopeIndex
, profiles
) {
50 ${(profiles || []).map((profile) => renderProfileHeader(profile)).join('\n')}
52 \t\t<th>Description</th>
53 \t\t<th>Application</th>
54 \t\t<th class="scope-actions"></th>
58 ${Object.entries(scopeIndex).sort(th.scopeCompare).map(([scope, details]) => renderScopeRow(scope, details, profiles)).join('\n')}
63 function _tokenType(token
) {
65 return 'ticket-token';
73 function renderTokenRow(token
) {
74 const createdTitle
= token
.refreshed
? 'Refreshed At' : 'Created At';
75 const createdDate
= token
.refreshed
? token
.refreshed : token
.created
;
77 <td>${_tokenType(token)}</td>
78 \t\t\t<td class="uri">${token.clientId}</td>
79 \t\t\t<td class="uri">${token.profile}</td>
80 <td class="scope">${(token.scopes || []).join(', ')}</td>
81 \t\t\t<td class="code">${token.codeId}</td>
82 \t\t\t<td>${th.timeElement(createdDate, { title: createdTitle })}</td>
83 \t\t\t<td>${th.timeElement(token.expires, { title: 'Expires At' })}</td>
84 \t\t\t<td>${token.isRevoked}</td>
85 <td>${token.resource ? token.resource : ''}</td>
87 token
.isRevoked
? '' : `
88 \t\t\t\t<button name="action" value="revoke-${token.codeId}">Revoke</button>`) + `
93 function noTokensRows() {
95 \t\t\t<td colspan="100%" class="centered">(No active or recent tokens.)</td>
99 function tokenTable(tokens
) {
100 const tokenRows
= tokens
?.length
? tokens
.map((token
) => renderTokenRow(token
)) : noTokensRows();
105 \t\t\t<th>Client Identifier</th>
106 \t\t\t<th>Profile</th>
109 \t\t\t<th>Created or Refreshed</th>
110 \t\t\t<th>Expires</th>
111 \t\t\t<th>Revoked</th>
117 ${tokenRows.join('\n')}
122 function mainContent(ctx
) {
126 \t${(ctx.profilesScopes?.profiles || []).map((p) => renderProfileLI(p)).join('\n')}
128 \t<form action="" method="POST">
130 \t\t\t<legend>Add New Profile</legend>
132 \t\t\t\tThe profile identity URIs associated with this account.
133 \t\t\t\tEach must indicate this service as the authorization endpoint.
136 \t\t\t<label for="profile">Profile URL:</label>
137 \t\t\t<input type="url" id="profile" name="profile" size="96">
138 \t\t\t<button name="action" value="new-profile">Add Profile</button>
144 \t<form action="" method="POST">
147 \t\tScopes Associated with Profiles for Convenience
150 \t\t\t\t<legend>Manage Additional Profile Scope Availability</legend>
152 \t\t\t\t\tThis table lists pre-defined scopes which you can choose to add to any authorization request, whether the client requested them or not.
153 \t\t\t\t\tSelecting one for a profile makes it conveniently available for quick inclusion when authorizing a client request.
154 \t\t\t\t\tAny scope not in this table or not selected for a profile can always be added in the ad hoc field on the authorization request.
157 \t\t${scopeIndexTable(ctx.profilesScopes.scopeIndex, ctx.profilesScopes.profiles)}
158 \t\t\t\t<button name="action" value="save-scopes">Save</button>
162 \t\t<form action="" method="POST">
164 \t\t\t\t<legend>Add New Scope</legend>
165 \t\t\t\t<label for="scope">Scope:</label>
166 \t\t\t\t<input type="text" id="scope" name="scope">
167 \t\t\t\t<label for="description">Description:</label>
168 \t\t\t\t<input type="text" id="description" name="description">
169 \t\t\t\t<label for="application">Application:</label>
170 \t\t\t\t<input type="text" id="application" name="application">
171 \t\t\t\t<button name="action" value="new-scope">Add Scope</button>
178 \t<form action="" method="POST">
179 ${tokenTable(ctx.tokens)}
187 * @param {Object} ctx
188 * @param {Object} ctx.profilesScopes.scopeIndex
189 * @param {String[]} ctx.profilesScopes.profiles
190 * @param {Object[]} ctx.tokens
191 * @param {Object} options
192 * @param {Object} options.manager
193 * @param {String} options.manager.pageTitle
194 * @param {String} options.manager.logoUrl
195 * @param {String[]} options.manager.footerEntries
198 module
.exports
= (ctx
, options
) => {
199 const htmlOptions
= {
200 pageTitle: options
.manager
.pageTitle
,
201 logoUrl: options
.manager
.logoUrl
,
202 footerEntries: options
.manager
.footerEntries
,
213 return th
.htmlPage(1, ctx
, htmlOptions
, content
);