Remove the web console EPP endpoint

This removes the "create Domain/Host/Contact" forms that were supposed to be used instead of regular EPPs for CC-TLD that wanted to support it.

We're removing it because we don't use it and want to reduce unneeded code for the registry 3.0 migration.

Also, this is a security risk, as it allowed to do "billable actions" (creating a new domain for example) with the only authentication being access to the registrar's G Suite account.

This bypassed the certificate, IP whitelist, and EPP password, which is bad.

PUBLIC:
Remove the web console EPP endpoint

This removes the "create Domain/Host/Contact" forms that were supposed to be used instead of regular EPPs for CC-TLD that wanted to support it.

We're removing it because we don't use it and want to reduce unneeded code for the registry 3.0 migration.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=236244195
This commit is contained in:
guyben 2019-02-28 19:37:30 -08:00 committed by Weimin Yu
parent f12d368da3
commit dfad79759e
52 changed files with 58 additions and 3788 deletions

View file

@ -22,13 +22,9 @@ goog.require('goog.net.XhrIo');
goog.require('registry.Console');
goog.require('registry.Resource');
goog.require('registry.registrar.AdminSettings');
goog.require('registry.registrar.Contact');
goog.require('registry.registrar.ContactSettings');
goog.require('registry.registrar.ContactUs');
goog.require('registry.registrar.Dashboard');
goog.require('registry.registrar.Domain');
goog.require('registry.registrar.EppSession');
goog.require('registry.registrar.Host');
goog.require('registry.registrar.Resources');
goog.require('registry.registrar.SecuritySettings');
goog.require('registry.registrar.WhoisSettings');
@ -49,16 +45,13 @@ goog.forwardDeclare('registry.Component');
* @final
*/
registry.registrar.Console = function(params) {
registry.registrar.Console.base(this, 'constructor');
/**
* @type {!Object}
*/
// We have to define this before creating an EppSession because EppSession's
// constructor expects us to have it as an attribute.
this.params = params;
registry.registrar.Console.base(
this, 'constructor', new registry.registrar.EppSession(this));
/**
* Component that's currently embedded in the page.
* @type {?registry.Component}
@ -66,13 +59,9 @@ registry.registrar.Console = function(params) {
*/
this.component_ = null;
// XXX: This was in parent ctor but was triggering event dispatching before
// ready here.
this.history.setEnabled(true);
/**
* Last active nav element.
* @type {Element}
* @type {?Element}
*/
this.lastActiveNavElt;
@ -107,13 +96,6 @@ registry.registrar.Console = function(params) {
if (this.params.isAdmin) {
this.pageMap['admin-settings'] = registry.registrar.AdminSettings;
}
// sending EPPs through the console. Currently hidden (doesn't have a "tab")
// but still accessible if the user manually puts #domain (or other) in the
// fragment
this.pageMap['contact'] = registry.registrar.Contact;
this.pageMap['domain'] = registry.registrar.Domain;
this.pageMap['host'] = registry.registrar.Host;
};
goog.inherits(registry.registrar.Console, registry.Console);
@ -134,17 +116,7 @@ goog.inherits(registry.registrar.Console, registry.Console);
*/
registry.registrar.Console.prototype.handleHashChange = function() {
var hashToken = this.history.getToken();
// On page reloads, opening a new tab, etc. it's possible that the
// session cookie for a logged-in session exists, but the
// this.session is not yet aware, so come back here after syncing.
//
// XXX: Method should be refactored to avoid this 2-stage behavior.
if (!this.session.isEppLoggedIn()) {
this.session.login(goog.bind(this.handleHashChange, this));
return;
}
// Otherwise, a resource operation.
var parts = hashToken.split('/');
var type = '';
var id = '';

View file

@ -1,129 +0,0 @@
// Copyright 2017 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.Contact');
goog.require('goog.dom');
goog.require('registry.registrar.XmlResourceComponent');
goog.require('registry.soy.registrar.contact');
goog.require('registry.soy.registrar.contactepp');
goog.forwardDeclare('registry.registrar.Console');
/**
* The `Contact` class respresents a registry contact object and
* binds UI CRUD operations to it.
* @param {!registry.registrar.Console} console the
* console singleton.
* @constructor
* @extends {registry.registrar.XmlResourceComponent}
* @final
*/
registry.registrar.Contact = function(console) {
registry.registrar.Contact.base(
this, 'constructor',
/** @type {function()} */(registry.soy.registrar.contact.item),
registry.soy.registrar.contactepp,
console);
};
goog.inherits(registry.registrar.Contact,
registry.registrar.XmlResourceComponent);
/** @override */
registry.registrar.Contact.prototype.processItem = function() {
this.model.item = this.model['epp']['response']['resData']['contact:infData'];
if (!goog.isArray(this.model.item['contact:postalInfo'])) {
this.model.item['contact:postalInfo'] =
[this.model.item['contact:postalInfo']];
}
// XXX: Is this code necessary?
var fixPlus = function(val) {
var str = (val || '') + '';
if (str == '' || str.match(/\+.*/)) {
return str;
} else {
return '+' + str;
}
};
// Both of these are optional.
if (this.model.item['contact:voice']) {
this.model.item['contact:voice']['keyValue'] =
fixPlus(this.model.item['contact:voice']['keyValue']);
}
if (this.model.item['contact:voice']) {
this.model.item['contact:fax']['keyValue'] =
fixPlus(this.model.item['contact:fax']['keyValue']);
}
};
/** @override */
registry.registrar.Contact.prototype.setupEditor = function(objArgs) {
// For now always keep the first contact and make it i18n. Toggle button
// disables to enforce state.
//
// XXX: Should be simplified to make more modular.
var postalElt = goog.dom.getRequiredElement('contact-postalInfo');
var addPostalInfoBtn = goog.dom.getRequiredElement(
'domain-contact-postalInfo-add-button');
this.typeCounts['contact-postalInfo'] = postalElt.childNodes.length;
// 4 child nodes means both addresses are present:
// 2 data tables, the footer id elt and a hidden input.
var setupRemoveBtns = this.typeCounts['contact-postalInfo'] == 4;
if (setupRemoveBtns) {
this.appendRemoveBtn(/** @type {!Element} */ (postalElt.childNodes[0]));
this.appendRemoveBtn(/** @type {!Element} */ (postalElt.childNodes[1]));
} else {
addPostalInfoBtn.removeAttribute('disabled');
}
this.addRemBtnHandlers(
'contact-postalInfo',
function() {
return 'contact:postalInfo[1].contact:';
},
function() {
addPostalInfoBtn.setAttribute('disabled', true);
return null;
},
/** @type {function()} */ (registry.soy.registrar.contact.postalInfo),
{
item: {},
localized: true,
itemPrefix: 'contact:',
namePrefix: 'contact:postalInfo[1].contact:'
},
setupRemoveBtns);
};
/** @override */
registry.registrar.Contact.prototype.prepareCreate = function(params) {
params.nextId = params.item['contact:id'];
return registry.soy.registrar.contactepp.create(
/** @type {{clTrid: ?, item: ?}} */ (params)).toString();
};
/** @override */
registry.registrar.Contact.prototype.prepareUpdate = function(params) {
params.nextId = params.item['contact:id'];
return registry.soy.registrar.contactepp.update(
/** @type {{clTrid: ?, item: ?}} */(params)).toString();
};

View file

@ -221,7 +221,7 @@ registry.registrar.ContactSettings.prototype.prepareUpdate =
* Handler for contact save that navigates to that item on success.
* Does nothing on failure as UI will be left with error messages for
* the user to resolve.
* @param {!Object} rsp Decoded XML/JSON response from the server.
* @param {!Object} rsp Decoded JSON response from the server.
* @override
*/
registry.registrar.ContactSettings.prototype.handleCreateResponse =
@ -238,7 +238,7 @@ registry.registrar.ContactSettings.prototype.handleCreateResponse =
* Handler for contact delete that navigates back to the collection on success.
* Does nothing on failure as UI will be left with error messages for
* the user to resolve.
* @param {!Object} rsp Decoded XML/JSON response from the server.
* @param {!Object} rsp Decoded JSON response from the server.
* @override
*/
registry.registrar.ContactSettings.prototype.handleDeleteResponse =

View file

@ -40,10 +40,10 @@ registry.registrar.Dashboard = function(console) {
/** @private {number} */
this.x_ = 0;
/** @private {Element} */
/** @private {?Element} */
this.gear_ = null;
/** @private {goog.Timer} */
/** @private {?goog.Timer} */
this.timer_ = null;
};
goog.inherits(registry.registrar.Dashboard, registry.Component);
@ -63,14 +63,6 @@ registry.registrar.Dashboard.prototype.bindToDom = function(id) {
};
/**
* Do EPP logout.
*/
registry.registrar.Dashboard.prototype.doEppLogout = function() {
this.console.session.logout();
};
/**
* Let's do the twist.
* @private

View file

@ -1,167 +0,0 @@
// Copyright 2017 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.Domain');
goog.require('goog.json');
goog.require('registry.registrar.XmlResourceComponent');
goog.require('registry.soy.forms');
goog.require('registry.soy.registrar.domain');
goog.require('registry.soy.registrar.domainepp');
goog.require('registry.util');
goog.forwardDeclare('registry.registrar.Console');
/**
* CRUD for EPP domain objects.
* @param {!registry.registrar.Console} console
* @constructor
* @extends {registry.registrar.XmlResourceComponent}
* @final
*/
registry.registrar.Domain = function(console) {
registry.registrar.Domain.base(
this, 'constructor',
/** @type {function()} */ (registry.soy.registrar.domain.item),
registry.soy.registrar.domainepp,
console);
};
goog.inherits(registry.registrar.Domain,
registry.registrar.XmlResourceComponent);
/** @override */
registry.registrar.Domain.prototype.newModel = function() {
var newModel = {item: {'domain:period': ''}};
return newModel;
};
/**
* Prepare a fetch query for the domain by its id.
* @param {!Object} params should have a name field with a
* possibly extended domain name id of the form "example.tld:1234"
* where the 1234 is the domain application id assigned by the
* backend flows.
* @override
*/
registry.registrar.Domain.prototype.prepareFetch = function(params) {
return registry.soy.registrar.domainepp.info(
/** @type {{clTrid: ?, id: ?}} */ (params)).toString();
};
/** @override */
registry.registrar.Domain.prototype.processItem = function() {
this.model.item = this.model['epp']['response']['resData']['domain:infData'];
// Hoist extensions for easy soy access.
var extension = this.model['epp']['response']['extension'];
if (extension && extension['launch:infData']) {
var extendedInfData = extension['launch:infData'];
var mark = extendedInfData['mark:mark'];
if (mark) {
this.model.item['mark:mark'] = {'keyValue': goog.json.serialize(mark)};
}
}
// Wrap single item into an array.
if (this.model.item['domain:ns'] &&
this.model.item['domain:ns']['domain:hostObj']) {
var hostObj = this.model.item['domain:ns']['domain:hostObj'];
if (!goog.isArray(hostObj)) {
this.model.item['domain:ns']['domain:hostObj'] = [hostObj];
}
}
};
/** @override */
registry.registrar.Domain.prototype.setupEditor = function(objArgs) {
this.typeCounts['contact'] = objArgs.item['domain:contact'] ?
objArgs.item['domain:contact'].length : 0;
var ji = objArgs.item['domain:ns'];
this.typeCounts['host'] =
ji && ji['domain:hostObj'] ? ji['domain:hostObj'].length : 0;
this.formInputRowRemovable(
document.querySelectorAll('input.domain-hostObj[readonly]'));
this.formInputRowRemovable(
document.querySelectorAll('input.domain-contact[readonly]'));
this.addRemBtnHandlers(
'contact',
goog.bind(function() {
return 'domain:contact[' + this.typeCounts['contact'] + ']';
}, this),
goog.bind(function(newFieldName) {
return registry.util.renderBeforeRow(
'domain-contacts-footer',
/** @type {function()} */(registry.soy.forms.selectRow), {
label: 'Type',
name: newFieldName + '.@type',
options: ['admin', 'tech', 'billing']
});
}, this));
this.addRemBtnHandlers('host', goog.bind(function() {
return 'domain:ns.domain:hostObj[' + this.typeCounts['host'] + ']';
}, this));
};
/** @override */
registry.registrar.Domain.prototype.prepareCreate = function(params) {
var form = params.item;
params.nextId = form['domain:name'];
// The presence of this field is used to signal extended template, so remove
// if not used.
if (form['smd:encodedSignedMark'] == '') {
delete form['smd:encodedSignedMark'];
}
var xml = registry.soy.registrar.domainepp.create(
/** @type {{clTrid: ?, item: ?}} */(params));
return xml.toString();
};
/** @override */
registry.registrar.Domain.prototype.prepareUpdate =
function(params) {
var form = params.item;
var nextId = form['domain:name'];
params.nextId = nextId;
if (form['domain:contact']) {
this.addRem(form['domain:contact'], 'Contacts', params);
}
if (form['domain:ns'] && form['domain:ns']['domain:hostObj']) {
this.addRem(form['domain:ns']['domain:hostObj'], 'Hosts', params);
}
if (form['domain:ns'] && form['domain:ns']['domain:hostObj']) {
this.addRem(form['domain:ns']['domain:hostObj'], 'Hosts', params);
}
this.addRem(form['domain:contact'], 'Contacts', params);
var xml = registry.soy.registrar.domainepp.update(
/** @type {{clTrid: ?, item: ?}} */(params));
return xml.toString();
};

View file

@ -1,128 +0,0 @@
// Copyright 2017 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.EppSession');
goog.require('goog.Uri');
goog.require('registry.Session');
goog.require('registry.soy.registrar.epp');
goog.require('registry.util');
goog.require('registry.xml');
goog.forwardDeclare('registry.registrar.Console');
/**
* Session state for console.
* @param {!registry.registrar.Console} console
* @constructor
* @extends {registry.Session}
* @final
*/
registry.registrar.EppSession = function(console) {
registry.registrar.EppSession.base(
this, 'constructor',
new goog.Uri('/registrar-xhr')
.setParameterValue('clientId', console.params.clientId),
console.params.xsrfToken,
registry.Session.ContentType.EPP);
/**
* @type {!registry.registrar.Console}
*/
this.console = console;
/**
* @type {!boolean}
* @private
*/
this.isEppLoggedIn_ = false;
};
goog.inherits(registry.registrar.EppSession, registry.Session);
/**
* Whether the session has received an EPP success response to an EPP
* login attempt.
* @return {boolean} Whether the user is logged into an EPP session.
*/
registry.registrar.EppSession.prototype.isEppLoggedIn = function() {
return this.isEppLoggedIn_;
};
/**
* Get the clientId if the user is logged in, or throw Error.
* @throws Error if the user is not logged in.
* @return {string} the clientId.
*/
registry.registrar.EppSession.prototype.getClientId = function() {
return this.console.params.clientId;
};
/**
* Login or display butterbar info about error.
* @param {function()} successCb to be called on success.
*/
registry.registrar.EppSession.prototype.login = function(successCb) {
var eppArgs = {clId: this.console.params.clientId, clTrid: 'asdf-1235'};
this.send(
registry.soy.registrar.epp.login(eppArgs).getContent(),
goog.bind(function(xml) {
var result = xml['epp']['response']['result'];
var eppCode = result['@code'];
if (eppCode == '1000' || eppCode == '2002') {
// Success || Already logged in.
this.isEppLoggedIn_ = true;
successCb();
} else {
// Failure.
this.isEppLoggedIn_ = false;
registry.util.butter('login error: ' + eppCode);
}
}, this));
};
/**
* Logout or display butterbar info about error.
*/
registry.registrar.EppSession.prototype.logout = function() {
this.send(
registry.soy.registrar.epp.logout(
{clTrid: 'asdf-1235'}).getContent(),
goog.bind(function(xml) {
var result = xml['epp']['response']['result'];
var eppCode = result['@code'];
registry.util.butter(
'logout ' + eppCode + ': ' + result['msg']['keyValue']);
// Going to be safe here and force a login either way.
this.isEppLoggedIn_ = false;
}, this));
};
/**
* Send xml to the server.
* @param {string} xml Request document.
* @param {function(!Object)} callback For XhrIo result throws.
*/
registry.registrar.EppSession.prototype.send = function(xml, callback) {
var toXmlJsonCb = function(rspXml) {
callback(registry.xml.convertToJson(rspXml));
};
this.sendXhrIo(xml, toXmlJsonCb);
};

View file

@ -1,107 +0,0 @@
// Copyright 2017 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.Host');
goog.require('registry.registrar.XmlResourceComponent');
goog.require('registry.soy.registrar.host');
goog.require('registry.soy.registrar.hostepp');
goog.forwardDeclare('registry.registrar.Console');
/**
* CRUD for EPP host objects.
* @param {!registry.registrar.Console} console
* @constructor
* @extends {registry.registrar.XmlResourceComponent}
* @final
*/
registry.registrar.Host = function(console) {
registry.registrar.Host.base(
this, 'constructor',
registry.soy.registrar.host.item,
registry.soy.registrar.hostepp,
console);
};
goog.inherits(registry.registrar.Host,
registry.registrar.XmlResourceComponent);
/** @override */
registry.registrar.Host.prototype.processItem = function() {
this.model.item = this.model['epp']['response']['resData']['host:infData'];
if (this.model.item['host:addr']) {
if (!goog.isArray(this.model.item['host:addr'])) {
this.model.item['host:addr'] = [this.model.item['host:addr']];
}
} else {
this.model.item['host:addr'] = [];
}
};
/** @override */
registry.registrar.Host.prototype.setupEditor = function(objArgs) {
this.typeCounts['host-addr'] =
objArgs.item['host:addr'] ? objArgs.item['host:addr'].length : 0;
this.addRemBtnHandlers('host-addr', goog.bind(function() {
return 'host:addr[' + this.typeCounts['host-addr'] + ']';
}, this));
this.formInputRowRemovable(document.querySelectorAll('input[readonly]'));
};
/** @override */
registry.registrar.Host.prototype.prepareCreate = function(params) {
params.nextId = params.item['host:name'];
return registry.soy.registrar.hostepp.create(
/** @type {{clTrid: ?, item: ?}} */(params)).toString();
};
/** @override */
registry.registrar.Host.prototype.prepareUpdate = function(params) {
var form = params.item;
var addAddrs = [];
var remAddrs = [];
if (form['host:addr']) {
var oldAddrs = form['host:oldAddr'] || [];
var newAddrs = form['host:addr'];
var length = Math.max(oldAddrs.length, newAddrs.length);
for (var i = 0; i < length; i++) {
if (i >= oldAddrs.length) {
addAddrs.push(newAddrs[i]['value']);
} else if (i >= newAddrs.length) {
remAddrs.push(oldAddrs[i]['value']);
} else {
if (newAddrs[i]['value'] == oldAddrs[i]['value']) {
// Do nothing.
} else if (newAddrs[i]['value'] == '') {
remAddrs.push(oldAddrs[i]['value']);
} else {
remAddrs.push(oldAddrs[i]['value']);
addAddrs.push(newAddrs[i]['value']);
}
}
}
}
params.addAddrs = addAddrs;
params.remAddrs = remAddrs;
params.nextId = form['host:chgName'];
return registry.soy.registrar.hostepp.update(
/** @type {{clTrid: ?, item: ?}} */(params)).toString();
};

View file

@ -38,11 +38,10 @@ goog.require('registry.registrar.Console');
* @param {string} technicalDocsUrl
* @export
*/
registry.registrar.main = function(xsrfToken, clientId, isAdmin, isOwner,
productName, integrationEmail, supportEmail,
announcementsEmail, supportPhoneNumber,
technicalDocsUrl) {
new registry.registrar.Console({
registry.registrar.main = function(
xsrfToken, clientId, isAdmin, isOwner, productName, integrationEmail,
supportEmail, announcementsEmail, supportPhoneNumber, technicalDocsUrl) {
const console = new registry.registrar.Console({
xsrfToken: xsrfToken,
clientId: clientId,
isAdmin: isAdmin,
@ -54,4 +53,6 @@ registry.registrar.main = function(xsrfToken, clientId, isAdmin, isOwner,
supportPhoneNumber: supportPhoneNumber,
technicalDocsUrl: technicalDocsUrl
});
console.setUp();
};

View file

@ -1,219 +0,0 @@
// Copyright 2017 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.XmlResourceComponent');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('registry.EditItem');
goog.require('registry.util');
goog.forwardDeclare('registry.registrar.Console');
/**
* The ResourceComponent class respresents server state for a named
* resource and binds UI CRUD operations on it, or its constituent
* collection.
* @param {function()} itemTmpl
* @param {!Object} eppTmpls Epp xml templates for info requests.
* @param {!registry.registrar.Console} console
* @constructor
* @extends {registry.EditItem}
*/
registry.registrar.XmlResourceComponent = function(
itemTmpl, eppTmpls, console) {
registry.registrar.XmlResourceComponent.base(
this, 'constructor', console, itemTmpl, console.params.isOwner);
/** @type {!Object} */
this.eppTmpls = eppTmpls;
};
goog.inherits(registry.registrar.XmlResourceComponent, registry.EditItem);
/** @override */
registry.registrar.XmlResourceComponent.prototype.bindToDom =
function(id) {
// XXX: EPP resources still use null state.
registry.registrar.XmlResourceComponent.base(
this, 'bindToDom', (id || ''));
if (id) {
this.fetchItem(id);
} else {
// Start edit of empty object.
this.edit();
}
};
/** @override */
registry.registrar.XmlResourceComponent.prototype.fetchItem = function(id) {
var queryParams = {id: id, clTrid: 'abc-1234'};
var xml = this.prepareFetch(queryParams);
this.console.session.send(xml, goog.bind(this.handleFetchItem, this, id));
};
/** @override */
registry.registrar.XmlResourceComponent.prototype.handleFetchItem =
function(id, rsp) {
this.model = rsp;
var result = rsp['epp']['response']['result'];
var resCode = result['@code'];
// XXX: Should use enum.
if (resCode == 1000) { // OK
this.model.readonly = true;
this.processItem();
this.renderItem(this.model);
} else if (resCode == 2303) { // Missing
registry.util.butter(
'Could not find: "' + id + '". Please enter as "type/id"');
} else {
// includes general failure.
registry.util.butter(resCode + ':' + result['msg']['keyValue']);
}
};
/**
* Sublcasses should override to populate create queryParams with form
* fields as needed. `queryParams.nextId` MUST be set to the
* new object's ID.
* @param {!Object} queryParams
*/
registry.registrar.XmlResourceComponent.prototype.prepareCreate =
goog.abstractMethod;
/**
* Calls prepareCreate with template params and then send the returned
* XML to the server
* @override
*/
registry.registrar.XmlResourceComponent.prototype.sendCreate = function() {
var form = registry.util.parseForm('item');
var queryParams = {item: form, clTrid: 'abc-1234'};
var xml = this.prepareCreate(queryParams);
this.nextId = queryParams.nextId;
this.console.session.send(xml, goog.bind(this.handleUpdateResponse, this));
};
/**
* Calls prepareUpdate with template params and then send the returned
* XML to the server.
* @override
*/
registry.registrar.XmlResourceComponent.prototype.sendUpdate = function() {
var form = registry.util.parseForm('item');
var queryParams = {item: form, clTrid: 'abc-1234'};
var xml = this.prepareUpdate(queryParams);
this.nextId = queryParams.nextId;
this.console.session.send(xml, goog.bind(this.handleUpdateResponse, this));
};
/**
* Sublcasses should override to populate fetch queryParams with form
* fields as needed.
* @param {!Object} queryParams
* @return {string} EPP xml string
*/
registry.registrar.XmlResourceComponent.prototype.prepareFetch =
function(queryParams) {
return this.eppTmpls.info(queryParams).toString();
};
/** @override */
registry.registrar.XmlResourceComponent.prototype.handleUpdateResponse =
function(rsp) {
var result = rsp['epp']['response']['result'];
if (result['@code'] == 1000) {
// XXX: Consider timer, probably just as a seconds arg with impl in butter.
registry.util.butter('Saved.');
this.fetchItem(this.nextId || '');
this.nextId = null;
this.toggleEdit();
} else {
registry.util.butter(result['msg']['keyValue']);
}
return rsp;
};
/**
* Helper to add add/remove hosts/contacts on queryParams:
*
* queryParams[op + fieldType] = formFields.
*
* @param {Array.<Object>} formFields named form item representations
* that have an associated {op: (add|rem)} attribute.
* @param {string} fieldType capitalized pluralized type name, e.g. "Contacts".
* @param {!Object} queryParams
*/
registry.registrar.XmlResourceComponent.prototype.addRem =
function(formFields, fieldType, queryParams) {
var add = [];
var rem = [];
for (var i = 0; i < formFields.length; i++) {
var formField = formFields[i];
var op = formField['op'];
switch (op) {
case 'add':
add.push(formField);
break;
case 'rem':
rem.push(formField);
break;
default:
registry.util.log(
'Unknown op attribute ' + op + ' on form field:',
formField);
}
}
if (add.length > 0) {
queryParams['add' + fieldType] = add;
}
if (rem.length > 0) {
queryParams['rem' + fieldType] = rem;
}
};
/**
* Make the given form input rows removable.
* @param {NodeList} elts array of input elements.
* @param {function()=} opt_onclickCb called when remove button is clicked.
*/
registry.registrar.XmlResourceComponent.prototype.formInputRowRemovable =
function(elts, opt_onclickCb) {
for (var i = 0; i < elts.length; i++) {
var parent = goog.dom.getParentElement(elts[i]);
this.appendRemoveBtn(parent, goog.partial(function(elt) {
var eppRemInput = goog.dom.createDom(goog.dom.TagName.INPUT, {
'name': elt.name.replace(/\.value/, '.op'),
'value': 'rem',
'type': 'hidden'
});
goog.dom.appendChild(goog.dom.getParentElement(elt), eppRemInput);
goog.dom.classlist.add(
goog.dom.getParentElement(
goog.dom.getParentElement(elt)), goog.getCssName('hidden'));
}, elts[i]));
}
};