Add a button in the admin panel to check OT&E status of a registrar

For now, it only displays a status of "Passed: true|false" or an error message in simple text. In further work we will make the UI nicer.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=229971564
This commit is contained in:
gbrodman 2019-01-18 12:14:17 -08:00 committed by Ben McIlwain
parent 87ab149049
commit 5f87c3bff3
13 changed files with 195 additions and 82 deletions

View file

@ -31,10 +31,10 @@
<url-pattern>/registrar</url-pattern>
</servlet-mapping>
<!-- Registrar Self-serve Settings. -->
<!-- Registrar creation console. -->
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/registrar-settings</url-pattern>
<url-pattern>/registrar-create</url-pattern>
</servlet-mapping>
<!-- OT&E creation console. -->
@ -43,10 +43,16 @@
<url-pattern>/registrar-ote-setup</url-pattern>
</servlet-mapping>
<!-- Registrar creation console. -->
<!-- OT&E status console. -->
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/registrar-create</url-pattern>
<url-pattern>/registrar-ote-status</url-pattern>
</servlet-mapping>
<!-- Registrar Self-serve Settings. -->
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/registrar-settings</url-pattern>
</servlet-mapping>
<!-- Security config -->

View file

@ -19,7 +19,6 @@
* @externs
*/
/**
* @suppress {duplicate}
*/
@ -31,6 +30,24 @@ var registry = {};
*/
registry.json = {};
registry.json.ote = {};
/**
* @typedef {{
* clientId: string,
* completed: boolean
* }}
*/
registry.json.ote.OteStatusResult;
/**
* @typedef {{
* status: string,
* message: string,
* results: !Array.<registry.json.ote.OteStatusResult>
* }}
*/
registry.json.ote.OteStatusResponse;
/**

View file

@ -85,7 +85,7 @@ goog.inherits(registry.Component, goog.events.EventHandler);
/**
* Subclasses shold override this to implement panel display.
* Subclasses should override this to implement panel display.
* @param {string} id The target resource id.
*/
registry.Component.prototype.bindToDom = function(id) {

View file

@ -128,6 +128,7 @@ registry.EditItem.prototype.renderItem = function(objArgs) {
goog.soy.renderElement(goog.dom.getRequiredElement('reg-content'),
this.itemTmpl,
objArgs);
this.runAfterRender(objArgs);
};
@ -263,10 +264,21 @@ registry.EditItem.prototype.cancel = function() {
/**
* Called after this.renderItem(), to allow for further setup of
* editing.
*
* TODO(b/122661518): merge this with runAfterRender so we don't have two
* similar methods
* @param {!Object} objArgs
*/
registry.EditItem.prototype.setupEditor = function(objArgs) {};
/**
* Called at the end of this.renderItem() to allow for registration
* of listeners and other tasks that depend on the existence of the items in the
* DOM
* @param {!Object} objArgs
*/
registry.EditItem.prototype.runAfterRender = function(objArgs) {};
// XXX: These should really take @param {object} which is the form. Alas the
// only override which doesn't work this way, ResourceComponent.sendCreate

View file

@ -19,6 +19,8 @@ goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.events');
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');
@ -50,30 +52,75 @@ registry.registrar.AdminSettings.prototype.bindToDom = function(id) {
goog.dom.removeNode(goog.dom.getRequiredElement('reg-app-btn-back'));
};
/** @override */
registry.registrar.AdminSettings.prototype.setupEditor =
function(objArgs) {
goog.dom.classlist.add(goog.dom.getRequiredElement('tlds'),
goog.getCssName('editing'));
var tlds = goog.dom.getElementsByClass(goog.getCssName('tld'),
goog.dom.getRequiredElement('tlds'));
goog.array.forEach(tlds, function(tld) {
var remBtn = goog.dom.getChildren(tld)[0];
goog.events.listen(remBtn,
registry.registrar.AdminSettings.prototype.runAfterRender = function(objArgs) {
goog.events.listen(
goog.dom.getRequiredElement('btn-ote-status'),
goog.events.EventType.CLICK,
goog.bind(this.onTldRemove_, this, remBtn));
}, this);
this.typeCounts['reg-tlds'] = objArgs.allowedTlds ?
objArgs.allowedTlds.length : 0;
goog.events.listen(goog.dom.getRequiredElement('btn-add-tld'),
goog.events.EventType.CLICK,
this.onTldAdd_,
false,
this);
goog.bind(
this.oteStatusCheck_, this, objArgs.xsrfToken, objArgs.clientId),
false, this);
};
/** @override */
registry.registrar.AdminSettings.prototype.setupEditor = function(objArgs) {
goog.dom.classlist.add(
goog.dom.getRequiredElement('tlds'), goog.getCssName('editing'));
var tlds = goog.dom.getElementsByClass(
goog.getCssName('tld'), goog.dom.getRequiredElement('tlds'));
goog.array.forEach(tlds, function(tld) {
var remBtn = goog.dom.getChildren(tld)[0];
goog.events.listen(
remBtn, goog.events.EventType.CLICK,
goog.bind(this.onTldRemove_, this, remBtn));
}, this);
this.typeCounts['reg-tlds'] =
objArgs.allowedTlds ? objArgs.allowedTlds.length : 0;
goog.events.listen(
goog.dom.getRequiredElement('btn-add-tld'), goog.events.EventType.CLICK,
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
* @param {string} clientId
* @private
*/
registry.registrar.AdminSettings.prototype.oteStatusCheck_ = function(
xsrfToken, clientId) {
goog.net.XhrIo.send('/registrar-ote-status', function(e) {
var response =
/** @type {!registry.json.ote.OteStatusResponse} */
(e.target.getResponseJson(
registry.registrar.AdminSettings.PARSER_BREAKER_));
var message;
if (response.status === 'SUCCESS') {
var results = response.results[0];
message = 'Passed: '.concat(results.completed);
} else {
message = 'Error: '.concat(response.message);
}
var textParent = goog.dom.getRequiredElement('ote-status-area-parent');
if (!textParent.hasChildNodes()) {
var textElement = document.createElement('p');
textElement.id = 'ote-status-area';
textParent.appendChild(textElement);
}
textParent.firstElementChild.textContent = message;
}, 'POST', goog.json.serialize({'clientId': clientId}), {
'X-CSRF-Token': xsrfToken,
'Content-Type': 'application/json; charset=UTF-8'
});
};
/**
* Click handler for TLD add button.
@ -88,7 +135,8 @@ registry.registrar.AdminSettings.prototype.onTldAdd_ = function() {
goog.dom.appendChild(goog.dom.getRequiredElement('tlds'), tldElt);
var remBtn = goog.dom.getFirstElementChild(tldElt);
goog.dom.classlist.remove(remBtn, goog.getCssName('hidden'));
goog.events.listen(remBtn, goog.events.EventType.CLICK,
goog.events.listen(
remBtn, goog.events.EventType.CLICK,
goog.bind(this.onTldRemove_, this, remBtn));
this.typeCounts['reg-tlds']++;
tldInputElt.value = '';
@ -100,7 +148,6 @@ registry.registrar.AdminSettings.prototype.onTldAdd_ = function() {
* @param {!Element} remBtn The remove button.
* @private
*/
registry.registrar.AdminSettings.prototype.onTldRemove_ =
function(remBtn) {
registry.registrar.AdminSettings.prototype.onTldRemove_ = function(remBtn) {
goog.dom.removeNode(goog.dom.getParentElement(remBtn));
};

View file

@ -14,8 +14,6 @@
{namespace registry.soy.registrar.admin}
/** Registrar admin settings page for view and edit. */
{template .settings}
{@param allowedTlds: list<string>}
@ -48,6 +46,9 @@
<label class="{css('setting-label')}">OT&amp;E setup page</label>
<td class="{css('setting')}">
<p>Generate new OT&amp;E accounts <a href="/registrar-ote-setup">here</a>
</p></td>
</tr>
{call .oteStatus /}
</table>
</form>
{/template}
@ -64,3 +65,17 @@
<input name="{$name}" value="{$tld}" readonly>
</div>
{/template}
{template .oteStatus}
<tr class="{css('kd-settings-pane-section')}">
<td class="{css('setting')}">
<button
type="button"
id="btn-ote-status"
value="Check OT&amp;E status"
class="{css('kd-button')} {css('kd-button-submit')}">Check OT&amp;E status
</button>
</td>
<td id="ote-status-area-parent" class="{css('setting')}"></td>
</tr>
{/template}

View file

@ -31,7 +31,7 @@ public final class OteStatsTest {
@Before
public void init() throws Exception {
OteStatsTestHelper.setupHistoryEntries();
OteStatsTestHelper.setupHistoryEntries("blobio");
}
@Test

View file

@ -31,92 +31,95 @@ public final class OteStatsTestHelper {
private static HistoryEntry domainCreateHistoryEntry;
private static HistoryEntry domainRestoreHistoryEntry;
public static void setupHistoryEntries() throws IOException {
// TODO(b/122830156): Have this replicate the exact OT&E workflow with the correct client IDs
public static void setupHistoryEntries(String baseClientId) throws IOException {
persistPremiumList("default_sandbox_list", "sandbox,USD 1000");
OteAccountBuilder.forClientId(baseClientId).addContact("email@example.com").buildAndPersist();
String oteAccount1 = String.format("%s-1", baseClientId);
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_sunrise.xml"))
.build());
domainCreateHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_idn.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_claim_notice.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_anchor_tenant_fee_standard.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_dsdata.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_DELETE)
.setXmlBytes(getBytes("domain_delete.xml"))
.build());
domainRestoreHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_RESTORE)
.setXmlBytes(getBytes("domain_restore.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_APPROVE)
.setXmlBytes(getBytes("domain_transfer_approve.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_CANCEL)
.setXmlBytes(getBytes("domain_transfer_cancel.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_REJECT)
.setXmlBytes(getBytes("domain_transfer_reject.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_REQUEST)
.setXmlBytes(getBytes("domain_transfer_request.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.DOMAIN_UPDATE)
.setXmlBytes(getBytes("domain_update_with_secdns.xml"))
.build());
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.HOST_CREATE)
.setXmlBytes(getBytes("host_create_complete.xml"))
.build());
hostDeleteHistoryEntry =
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.HOST_DELETE)
.setXmlBytes(getBytes("host_delete.xml"))
.build());
@ -126,7 +129,7 @@ public final class OteStatsTestHelper {
for (int i = 0; i < 10; i++) {
persistResource(
new HistoryEntry.Builder()
.setClientId("blobio-1")
.setClientId(oteAccount1)
.setType(Type.HOST_UPDATE)
.setXmlBytes(getBytes("host_update.xml"))
.setTrid(Trid.create(null, String.format("blahtrid-%d", i)))

View file

@ -34,6 +34,7 @@ java_library(
srcs = ["Fixture.java"],
deps = [
"//java/google/registry/model",
"//javatests/google/registry/model",
"//javatests/google/registry/testing",
"//third_party/objectify:objectify-v4_1",
"@com_google_appengine_api_1_0_sdk",

View file

@ -28,6 +28,8 @@ import static google.registry.testing.DatastoreHelper.persistResource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.model.OteAccountBuilder;
import google.registry.model.OteStatsTestHelper;
import google.registry.model.contact.ContactAddress;
import google.registry.model.contact.ContactResource;
import google.registry.model.contact.PostalInfo;
@ -35,6 +37,7 @@ import google.registry.model.domain.DesignatedContact;
import google.registry.model.ofy.Ofy;
import google.registry.testing.FakeClock;
import google.registry.testing.InjectRule;
import java.io.IOException;
import org.joda.time.DateTime;
/**
@ -62,6 +65,13 @@ public enum Fixture {
// Used for OT&E TLDs
persistPremiumList("default_sandbox_list");
OteAccountBuilder.forClientId("oteunfinished").addContact("email@example.com").buildAndPersist();
try {
OteStatsTestHelper.setupHistoryEntries("otefinished");
} catch (IOException e) {
throw new RuntimeException(e);
}
ContactResource google = persistResource(newContactResource("google")
.asBuilder()
.setLocalizedPostalInfo(new PostalInfo.Builder()

View file

@ -53,7 +53,8 @@ public final class RegistryTestServer {
Paths.get("../domain_registry/java/google/registry/ui/assets"))
.build();
private static final ImmutableList<Route> ROUTES = ImmutableList.of(
private static final ImmutableList<Route> ROUTES =
ImmutableList.of(
// Frontend Services
route("/whois/*", FrontendServlet.class),
route("/rdap/*", FrontendServlet.class),
@ -85,9 +86,10 @@ public final class RegistryTestServer {
// Registrar Console
route("/registrar", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class),
route("/registrar-create", FrontendServlet.class),
route("/registrar-ote-setup", FrontendServlet.class),
route("/registrar-create", FrontendServlet.class));
route("/registrar-ote-status", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class));
private static final ImmutableList<Class<? extends Filter>> FILTERS = ImmutableList.of(
ObjectifyFilter.class,

View file

@ -38,7 +38,7 @@ public class VerifyOteActionTest {
@Before
public void init() throws Exception {
OteStatsTestHelper.setupHistoryEntries();
OteStatsTestHelper.setupHistoryEntries("blobio");
}
@Test

View file

@ -52,11 +52,11 @@ public final class OteStatusActionTest {
@Before
public void init() throws Exception {
OteStatsTestHelper.setupHistoryEntries();
OteStatsTestHelper.setupHistoryEntries(BASE_CLIENT_ID);
persistNewRegistrar(CLIENT_ID, "SomeRegistrar", Type.OTE, null);
ImmutableSetMultimap<String, Role> authValues =
OteAccountBuilder.createClientIdToTldMap("blobio").keySet().stream()
OteAccountBuilder.createClientIdToTldMap(BASE_CLIENT_ID).keySet().stream()
.collect(toImmutableSetMultimap(Function.identity(), ignored -> Role.OWNER));
action.registrarAccessor = AuthenticatedRegistrarAccessor.createForTesting(authValues);
}