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

View file

@ -19,7 +19,6 @@
* @externs * @externs
*/ */
/** /**
* @suppress {duplicate} * @suppress {duplicate}
*/ */
@ -31,6 +30,24 @@ var registry = {};
*/ */
registry.json = {}; 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. * @param {string} id The target resource id.
*/ */
registry.Component.prototype.bindToDom = function(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'), goog.soy.renderElement(goog.dom.getRequiredElement('reg-content'),
this.itemTmpl, this.itemTmpl,
objArgs); objArgs);
this.runAfterRender(objArgs);
}; };
@ -263,10 +264,21 @@ registry.EditItem.prototype.cancel = function() {
/** /**
* Called after this.renderItem(), to allow for further setup of * Called after this.renderItem(), to allow for further setup of
* editing. * editing.
*
* TODO(b/122661518): merge this with runAfterRender so we don't have two
* similar methods
* @param {!Object} objArgs * @param {!Object} objArgs
*/ */
registry.EditItem.prototype.setupEditor = function(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 // XXX: These should really take @param {object} which is the form. Alas the
// only override which doesn't work this way, ResourceComponent.sendCreate // 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.dom.classlist');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('goog.json');
goog.require('goog.net.XhrIo');
goog.require('goog.soy'); goog.require('goog.soy');
goog.require('registry.Resource'); goog.require('registry.Resource');
goog.require('registry.ResourceComponent'); 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')); goog.dom.removeNode(goog.dom.getRequiredElement('reg-app-btn-back'));
}; };
/** @override */ /** @override */
registry.registrar.AdminSettings.prototype.setupEditor = registry.registrar.AdminSettings.prototype.runAfterRender = function(objArgs) {
function(objArgs) { goog.events.listen(
goog.dom.classlist.add(goog.dom.getRequiredElement('tlds'), goog.dom.getRequiredElement('btn-ote-status'),
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.events.EventType.CLICK,
goog.bind(this.onTldRemove_, this, remBtn)); goog.bind(
}, this); this.oteStatusCheck_, this, objArgs.xsrfToken, objArgs.clientId),
this.typeCounts['reg-tlds'] = objArgs.allowedTlds ? false, this);
objArgs.allowedTlds.length : 0;
goog.events.listen(goog.dom.getRequiredElement('btn-add-tld'),
goog.events.EventType.CLICK,
this.onTldAdd_,
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. * Click handler for TLD add button.
@ -88,7 +135,8 @@ registry.registrar.AdminSettings.prototype.onTldAdd_ = function() {
goog.dom.appendChild(goog.dom.getRequiredElement('tlds'), tldElt); goog.dom.appendChild(goog.dom.getRequiredElement('tlds'), tldElt);
var remBtn = goog.dom.getFirstElementChild(tldElt); var remBtn = goog.dom.getFirstElementChild(tldElt);
goog.dom.classlist.remove(remBtn, goog.getCssName('hidden')); 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)); goog.bind(this.onTldRemove_, this, remBtn));
this.typeCounts['reg-tlds']++; this.typeCounts['reg-tlds']++;
tldInputElt.value = ''; tldInputElt.value = '';
@ -100,7 +148,6 @@ registry.registrar.AdminSettings.prototype.onTldAdd_ = function() {
* @param {!Element} remBtn The remove button. * @param {!Element} remBtn The remove button.
* @private * @private
*/ */
registry.registrar.AdminSettings.prototype.onTldRemove_ = registry.registrar.AdminSettings.prototype.onTldRemove_ = function(remBtn) {
function(remBtn) {
goog.dom.removeNode(goog.dom.getParentElement(remBtn)); goog.dom.removeNode(goog.dom.getParentElement(remBtn));
}; };

View file

@ -14,8 +14,6 @@
{namespace registry.soy.registrar.admin} {namespace registry.soy.registrar.admin}
/** Registrar admin settings page for view and edit. */ /** Registrar admin settings page for view and edit. */
{template .settings} {template .settings}
{@param allowedTlds: list<string>} {@param allowedTlds: list<string>}
@ -48,6 +46,9 @@
<label class="{css('setting-label')}">OT&amp;E setup page</label> <label class="{css('setting-label')}">OT&amp;E setup page</label>
<td class="{css('setting')}"> <td class="{css('setting')}">
<p>Generate new OT&amp;E accounts <a href="/registrar-ote-setup">here</a> <p>Generate new OT&amp;E accounts <a href="/registrar-ote-setup">here</a>
</p></td>
</tr>
{call .oteStatus /}
</table> </table>
</form> </form>
{/template} {/template}
@ -64,3 +65,17 @@
<input name="{$name}" value="{$tld}" readonly> <input name="{$name}" value="{$tld}" readonly>
</div> </div>
{/template} {/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 @Before
public void init() throws Exception { public void init() throws Exception {
OteStatsTestHelper.setupHistoryEntries(); OteStatsTestHelper.setupHistoryEntries("blobio");
} }
@Test @Test

View file

@ -31,92 +31,95 @@ public final class OteStatsTestHelper {
private static HistoryEntry domainCreateHistoryEntry; private static HistoryEntry domainCreateHistoryEntry;
private static HistoryEntry domainRestoreHistoryEntry; 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"); persistPremiumList("default_sandbox_list", "sandbox,USD 1000");
OteAccountBuilder.forClientId(baseClientId).addContact("email@example.com").buildAndPersist();
String oteAccount1 = String.format("%s-1", baseClientId);
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE) .setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_sunrise.xml")) .setXmlBytes(getBytes("domain_create_sunrise.xml"))
.build()); .build());
domainCreateHistoryEntry = domainCreateHistoryEntry =
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE) .setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_idn.xml")) .setXmlBytes(getBytes("domain_create_idn.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE) .setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_claim_notice.xml")) .setXmlBytes(getBytes("domain_create_claim_notice.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE) .setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_anchor_tenant_fee_standard.xml")) .setXmlBytes(getBytes("domain_create_anchor_tenant_fee_standard.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_CREATE) .setType(Type.DOMAIN_CREATE)
.setXmlBytes(getBytes("domain_create_dsdata.xml")) .setXmlBytes(getBytes("domain_create_dsdata.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_DELETE) .setType(Type.DOMAIN_DELETE)
.setXmlBytes(getBytes("domain_delete.xml")) .setXmlBytes(getBytes("domain_delete.xml"))
.build()); .build());
domainRestoreHistoryEntry = domainRestoreHistoryEntry =
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_RESTORE) .setType(Type.DOMAIN_RESTORE)
.setXmlBytes(getBytes("domain_restore.xml")) .setXmlBytes(getBytes("domain_restore.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_APPROVE) .setType(Type.DOMAIN_TRANSFER_APPROVE)
.setXmlBytes(getBytes("domain_transfer_approve.xml")) .setXmlBytes(getBytes("domain_transfer_approve.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_CANCEL) .setType(Type.DOMAIN_TRANSFER_CANCEL)
.setXmlBytes(getBytes("domain_transfer_cancel.xml")) .setXmlBytes(getBytes("domain_transfer_cancel.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_REJECT) .setType(Type.DOMAIN_TRANSFER_REJECT)
.setXmlBytes(getBytes("domain_transfer_reject.xml")) .setXmlBytes(getBytes("domain_transfer_reject.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_TRANSFER_REQUEST) .setType(Type.DOMAIN_TRANSFER_REQUEST)
.setXmlBytes(getBytes("domain_transfer_request.xml")) .setXmlBytes(getBytes("domain_transfer_request.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.DOMAIN_UPDATE) .setType(Type.DOMAIN_UPDATE)
.setXmlBytes(getBytes("domain_update_with_secdns.xml")) .setXmlBytes(getBytes("domain_update_with_secdns.xml"))
.build()); .build());
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.HOST_CREATE) .setType(Type.HOST_CREATE)
.setXmlBytes(getBytes("host_create_complete.xml")) .setXmlBytes(getBytes("host_create_complete.xml"))
.build()); .build());
hostDeleteHistoryEntry = hostDeleteHistoryEntry =
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.HOST_DELETE) .setType(Type.HOST_DELETE)
.setXmlBytes(getBytes("host_delete.xml")) .setXmlBytes(getBytes("host_delete.xml"))
.build()); .build());
@ -126,7 +129,7 @@ public final class OteStatsTestHelper {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
persistResource( persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setClientId("blobio-1") .setClientId(oteAccount1)
.setType(Type.HOST_UPDATE) .setType(Type.HOST_UPDATE)
.setXmlBytes(getBytes("host_update.xml")) .setXmlBytes(getBytes("host_update.xml"))
.setTrid(Trid.create(null, String.format("blahtrid-%d", i))) .setTrid(Trid.create(null, String.format("blahtrid-%d", i)))

View file

@ -34,6 +34,7 @@ java_library(
srcs = ["Fixture.java"], srcs = ["Fixture.java"],
deps = [ deps = [
"//java/google/registry/model", "//java/google/registry/model",
"//javatests/google/registry/model",
"//javatests/google/registry/testing", "//javatests/google/registry/testing",
"//third_party/objectify:objectify-v4_1", "//third_party/objectify:objectify-v4_1",
"@com_google_appengine_api_1_0_sdk", "@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.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key; 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.ContactAddress;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
import google.registry.model.contact.PostalInfo; 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.model.ofy.Ofy;
import google.registry.testing.FakeClock; import google.registry.testing.FakeClock;
import google.registry.testing.InjectRule; import google.registry.testing.InjectRule;
import java.io.IOException;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** /**
@ -62,6 +65,13 @@ public enum Fixture {
// Used for OT&E TLDs // Used for OT&E TLDs
persistPremiumList("default_sandbox_list"); 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") ContactResource google = persistResource(newContactResource("google")
.asBuilder() .asBuilder()
.setLocalizedPostalInfo(new PostalInfo.Builder() .setLocalizedPostalInfo(new PostalInfo.Builder()

View file

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

View file

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

View file

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