mirror of
https://github.com/google/nomulus.git
synced 2025-06-21 03:40:47 +02:00
Add Registry Lock UI (#369)
* Add Registry Lock UI * Responses to CRs, mostly TODO: - Figure out wording for the 'not enabled yet' message - Include the server status change cost in the email, or in the UI? - Should we show non-completed lock requests in the UI? * Fix get action test * Change the not-allowed-for-registrar msg to include support email * Change the wording on the price * Move TLD input into the modal, and other changes - don't log the password - test to make sure the password shows bullets * Responses to CR and cleanup * Format closer to something proper
This commit is contained in:
parent
1f77c19ba7
commit
af9237e3f9
50 changed files with 548 additions and 22 deletions
|
@ -0,0 +1,47 @@
|
|||
/** Registry Lock */
|
||||
|
||||
.new-registry-lock #lock-domain-input {
|
||||
width: 50%
|
||||
}
|
||||
|
||||
.new-registry-lock #lock-domain-submit {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.registry-locks-table {
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
.registry-locks-table td {
|
||||
padding: 0.5em 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.lock-confirm-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0,0,0,0.8);
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.lock-confirm-modal > div {
|
||||
width: 400px;
|
||||
position: relative;
|
||||
margin: 10% auto;
|
||||
padding: 5px 20px 13px 20px;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.lock-confirm-modal .buttons-div {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.lock-confirm-modal button {
|
||||
margin-left: 10px
|
||||
}
|
|
@ -30,6 +30,37 @@ var registry = {};
|
|||
*/
|
||||
registry.json = {};
|
||||
|
||||
registry.json.locks = {};
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* fullyQualifiedDomainName: string,
|
||||
* lockedTime: string,
|
||||
* lockedBy: string,
|
||||
* userCanUnlock: boolean
|
||||
* }}
|
||||
*/
|
||||
registry.json.locks.ExistingLock;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* clientId: string,
|
||||
* email: string,
|
||||
* details: !Array.<registry.json.locks.ExistingLock>,
|
||||
* lockEnabledForContact: boolean
|
||||
* }}
|
||||
*/
|
||||
registry.json.locks.ExistingLocksResult;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* status: string,
|
||||
* message: string,
|
||||
* results: !Array.<registry.json.locks.ExistingLocksResult>
|
||||
* }}
|
||||
*/
|
||||
registry.json.locks.ExistingLocksResponse;
|
||||
|
||||
registry.json.ote = {};
|
||||
|
||||
/**
|
||||
|
|
|
@ -84,13 +84,6 @@ registry.registrar.AdminSettings.prototype.setupEditor = function(objArgs) {
|
|||
this.onTldAdd_, false, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* JSON response prefix which prevents evaluation.
|
||||
* @private {string}
|
||||
* @const
|
||||
*/
|
||||
registry.registrar.AdminSettings.PARSER_BREAKER_ = ')]}\'\n';
|
||||
|
||||
/**
|
||||
* Click handler for OT&E status checking button.
|
||||
* @param {string} xsrfToken
|
||||
|
@ -102,8 +95,7 @@ registry.registrar.AdminSettings.prototype.oteStatusCheck_ = function(
|
|||
goog.net.XhrIo.send('/registrar-ote-status', function(e) {
|
||||
var response =
|
||||
/** @type {!registry.json.ote.OteStatusResponse} */
|
||||
(e.target.getResponseJson(
|
||||
registry.registrar.AdminSettings.PARSER_BREAKER_));
|
||||
(e.target.getResponseJson(registry.Resource.PARSER_BREAKER_));
|
||||
var oteResultParent = goog.dom.getRequiredElement('ote-status-area-parent');
|
||||
if (response.status === 'SUCCESS') {
|
||||
var results = response.results[0];
|
||||
|
|
|
@ -25,6 +25,7 @@ goog.require('registry.registrar.AdminSettings');
|
|||
goog.require('registry.registrar.ContactSettings');
|
||||
goog.require('registry.registrar.ContactUs');
|
||||
goog.require('registry.registrar.Dashboard');
|
||||
goog.require('registry.registrar.RegistryLock');
|
||||
goog.require('registry.registrar.Resources');
|
||||
goog.require('registry.registrar.SecuritySettings');
|
||||
goog.require('registry.registrar.WhoisSettings');
|
||||
|
@ -82,6 +83,10 @@ registry.registrar.Console = function(params) {
|
|||
this.pageMap['whois-settings'] = registry.registrar.WhoisSettings;
|
||||
this.pageMap['contact-us'] = registry.registrar.ContactUs;
|
||||
this.pageMap['resources'] = registry.registrar.Resources;
|
||||
// Registry lock is enabled or not per registrar, but since we don't have the registrar object
|
||||
// accessible here yet, show the link no matter what (the page will show an error message if
|
||||
// registry lock isn't enabled for this registrar)
|
||||
this.pageMap['registry-lock'] = registry.registrar.RegistryLock;
|
||||
// For admin use. The relevant tab is only shown in Console.soy for admins,
|
||||
// but we also need to remove it here, otherwise it'd still be accessible if
|
||||
// the user manually puts '#admin-settings' in the URL.
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
goog.provide('registry.registrar.RegistryLock');
|
||||
|
||||
goog.forwardDeclare('registry.registrar.Console');
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.classlist');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.KeyCodes');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.json');
|
||||
goog.require('goog.net.XhrIo');
|
||||
goog.require('goog.soy');
|
||||
goog.require('registry.Resource');
|
||||
goog.require('registry.ResourceComponent');
|
||||
goog.require('registry.soy.registrar.registrylock');
|
||||
|
||||
|
||||
/**
|
||||
* Registry Lock page, allowing the user to lock / unlock domains.
|
||||
* @param {!registry.registrar.Console} console
|
||||
* @param {!registry.Resource} resource the RESTful resource for the registrar.
|
||||
* @constructor
|
||||
* @extends {registry.ResourceComponent}
|
||||
* @final
|
||||
*/
|
||||
registry.registrar.RegistryLock = function(console, resource) {
|
||||
registry.registrar.RegistryLock.base(
|
||||
this, 'constructor', console, resource,
|
||||
registry.soy.registrar.registrylock.settings, false, null);
|
||||
};
|
||||
goog.inherits(registry.registrar.RegistryLock, registry.ResourceComponent);
|
||||
|
||||
registry.registrar.RegistryLock.prototype.runAfterRender = function(objArgs) {
|
||||
this.clientId = objArgs.clientId;
|
||||
this.xsrfToken = objArgs.xsrfToken;
|
||||
|
||||
if (objArgs.registryLockAllowed) {
|
||||
// Load the existing locks and display them in the table
|
||||
goog.net.XhrIo.send(
|
||||
'/registry-lock-get?clientId=' + objArgs.clientId, e => this.fillLocksPage_(e));
|
||||
} else {
|
||||
goog.soy.renderElement(
|
||||
goog.dom.getRequiredElement('locks-content'),
|
||||
registry.soy.registrar.registrylock.lockNotAllowedOnRegistrar,
|
||||
{supportEmail: objArgs.supportEmail});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the lock/unlock-confirmation modal if it exists
|
||||
* @private
|
||||
*/
|
||||
const removeModalIfExists_ = function() {
|
||||
var modalElement = goog.dom.getElement('lock-confirm-modal');
|
||||
if (modalElement != null) {
|
||||
modalElement.parentElement.removeChild(modalElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the modal and displays the locks content (lock a new domain, existing locks) that was
|
||||
* retrieved from the server.
|
||||
* @private
|
||||
*/
|
||||
registry.registrar.RegistryLock.prototype.fillLocksPage_ = function(e) {
|
||||
var response =
|
||||
/** @type {!registry.json.locks.ExistingLocksResponse} */
|
||||
(e.target.getResponseJson(registry.Resource.PARSER_BREAKER_));
|
||||
if (response.status === 'SUCCESS') {
|
||||
removeModalIfExists_();
|
||||
var locksDetails = response.results[0]
|
||||
var locksContentDiv = goog.dom.getRequiredElement('locks-content');
|
||||
goog.soy.renderElement(
|
||||
locksContentDiv,
|
||||
registry.soy.registrar.registrylock.locksContent,
|
||||
{locks: locksDetails.locks,
|
||||
email: locksDetails.email,
|
||||
lockEnabledForContact: locksDetails.lockEnabledForContact});
|
||||
|
||||
if (locksDetails.lockEnabledForContact) {
|
||||
// Listen to the lock-domain 'submit' button click as well as the enter key
|
||||
var lockButton = goog.dom.getRequiredElement('button-lock-domain');
|
||||
goog.events.listen(lockButton, goog.events.EventType.CLICK, this.onLockDomain_, false, this);
|
||||
// For all unlock buttons, listen and perform the unlock action if they're clicked
|
||||
var unlockButtons = goog.dom.getElementsByClass('domain-unlock-button', locksContentDiv);
|
||||
unlockButtons.forEach(button =>
|
||||
goog.events.listen(button, goog.events.EventType.CLICK, this.onUnlockDomain_, false, this));
|
||||
}
|
||||
} else {
|
||||
var errorDiv = goog.dom.getRequiredElement('modal-error-message');
|
||||
errorDiv.textContent = response.message;
|
||||
errorDiv.removeAttribute('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the lock/unlock confirmation modal
|
||||
* @private
|
||||
*/
|
||||
registry.registrar.RegistryLock.prototype.showModal_ = function(targetElement, domain, isLock) {
|
||||
var parentElement = targetElement.parentElement;
|
||||
// attach the modal to the parent element so focus remains correct if the user closes the modal
|
||||
var modalElement = goog.soy.renderAsElement(
|
||||
registry.soy.registrar.registrylock.confirmModal, {domain: domain, isLock: isLock});
|
||||
parentElement.prepend(modalElement);
|
||||
goog.dom.getRequiredElement('domain-lock-password').focus();
|
||||
// delete the modal when the user clicks the cancel button
|
||||
goog.events.listen(
|
||||
goog.dom.getRequiredElement('domain-lock-cancel'),
|
||||
goog.events.EventType.CLICK,
|
||||
removeModalIfExists_,
|
||||
false,
|
||||
this);
|
||||
|
||||
goog.events.listen(
|
||||
goog.dom.getRequiredElement('domain-lock-submit'),
|
||||
goog.events.EventType.CLICK,
|
||||
e => this.lockOrUnlockDomain_(isLock, e),
|
||||
false,
|
||||
this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks or unlocks the specified domain
|
||||
* @private
|
||||
*/
|
||||
registry.registrar.RegistryLock.prototype.lockOrUnlockDomain_ = function(isLock, e) {
|
||||
var domain = goog.dom.getRequiredElement('domain-lock-input-value').value;
|
||||
var password = goog.dom.getRequiredElement('domain-lock-password').value;
|
||||
goog.net.XhrIo.send('/registry-lock-post',
|
||||
e => this.fillLocksPage_(e),
|
||||
'POST',
|
||||
goog.json.serialize({
|
||||
'clientId': this.clientId,
|
||||
'fullyQualifiedDomainName': domain,
|
||||
'isLock': isLock,
|
||||
'password': password
|
||||
}), {
|
||||
'X-CSRF-Token': this.xsrfToken,
|
||||
'Content-Type': 'application/json; charset=UTF-8'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Click handler for unlocking domains (button click).
|
||||
* @private
|
||||
*/
|
||||
registry.registrar.RegistryLock.prototype.onUnlockDomain_ = function(e) {
|
||||
// the domain is stored in the button ID if it's the right type of button
|
||||
var idRegex = /button-unlock-(.*)/
|
||||
var targetId = e.target.id;
|
||||
var match = targetId.match(idRegex);
|
||||
if (match) {
|
||||
var domain = match[1];
|
||||
this.showModal_(e.target, domain, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Click handler for lock-domain button.
|
||||
* @private
|
||||
*/
|
||||
registry.registrar.RegistryLock.prototype.onLockDomain_ = function(e) {
|
||||
this.showModal_(e.target, null, true);
|
||||
};
|
|
@ -78,3 +78,9 @@ registry.Resource.prototype.send_ =
|
|||
req['id'] = this.id_;
|
||||
this.sendXhrIo(goog.json.serialize(req), callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* JSON response prefix which prevents evaluation.
|
||||
* @const
|
||||
*/
|
||||
registry.Resource.PARSER_BREAKER_ = ')]}\'\n';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue