1
0
mirror of https://github.com/google/nomulus synced 2026-04-16 22:47:30 +00:00

Remove old console soy/js and related files (#2861)

We haven't been serving this for a while, let's finally get rid of them.

We keep some Soy rules around in the presubmits file because we use some
Soy files as XML templates for EPP actions.
This commit is contained in:
gbrodman
2025-10-28 16:34:34 -04:00
committed by GitHub
parent ad07b32638
commit 754e7fbddc
53 changed files with 3 additions and 14131 deletions

View File

@@ -105,9 +105,8 @@ PRESUBMITS = {
# System.(out|err).println should only appear in tools/ or load-testing/
PresubmitCheck(
r".*\bSystem\.(out|err)\.print", "java", {
"StackdriverDashboardBuilder.java", "/tools/", "/example/",
"/load-testing/", "RegistryTestServerMain.java",
"TestServerExtension.java", "FlowDocumentationTool.java"
"/tools/", "/example/", "/load-testing/",
"RegistryTestServerMain.java", "TestServerExtension.java"
}):
"System.(out|err).println is only allowed in tools/ packages. Please "
"use a logger instead.",
@@ -120,7 +119,7 @@ PRESUBMITS = {
):
"In SOY please use the ({@param name: string} /** User name. */) style"
" parameter passing instead of the ( * @param name User name.) style "
"parameter pasing.",
"parameter passing.",
PresubmitCheck(
r'.*\{[^}]+\w+:\s+"',
"soy",
@@ -139,41 +138,6 @@ PRESUBMITS = {
{},
):
"All soy templates must use strict autoescaping",
# various JS linting checks
PresubmitCheck(
r".*goog\.base\(",
"js",
{"/node_modules/"},
):
"Use of goog.base is not allowed.",
PresubmitCheck(
r".*goog\.dom\.classes",
"js",
{"/node_modules/"},
):
"Instead of goog.dom.classes, use goog.dom.classlist which is smaller "
"and faster.",
PresubmitCheck(
r".*goog\.getMsg",
"js",
{"/node_modules/"},
):
"Put messages in Soy, instead of using goog.getMsg().",
PresubmitCheck(
r".*(innerHTML|outerHTML)\s*(=|[+]=)([^=]|$)",
"js",
{"/node_modules/", "registrar_bin."},
):
"Do not assign directly to the dom. Use goog.dom.setTextContent to set"
" to plain text, goog.dom.removeChildren to clear, or "
"soy.renderElement to render anything else",
PresubmitCheck(
r".*console\.(log|info|warn|error)",
"js",
{"/node_modules/", "google/registry/ui/js/util.js", "registrar_bin."},
):
"JavaScript files should not include console logging.",
PresubmitCheck(
r".*\nimport (static )?.*\.shaded\..*",
"java",
@@ -303,26 +267,6 @@ def verify_flyway_index():
return not success
def verify_javascript_deps():
"""Verifies that we haven't introduced any new javascript dependencies."""
with open('package.json') as f:
package = json.load(f)
deps = list(package['dependencies'].keys())
if deps != EXPECTED_JS_PACKAGES:
print('Unexpected javascript dependencies. Was expecting '
'%s, got %s.' % (EXPECTED_JS_PACKAGES, deps))
print(textwrap.dedent("""
* If the new dependencies are intentional, please verify that the
* license is one of the allowed licenses (see
* config/dependency-license/allowed_licenses.json) and add an entry
* for the package (with the license in a comment) to the
* EXPECTED_JS_PACKAGES variable in config/presubmits.py.
"""))
return True
return False
def get_files():
for root, dirnames, filenames in os.walk("."):
for filename in filenames:
@@ -347,8 +291,5 @@ if __name__ == "__main__":
# when we put it here it fails fast before all of the tests are run.
failed |= verify_flyway_index()
# Make sure we haven't introduced any javascript dependencies.
failed |= verify_javascript_deps()
if failed:
sys.exit(1)

View File

@@ -30,7 +30,6 @@ def screenshotsForGoldensDir = "${project.buildDir}/screenshots_for_goldens"
def newGoldensDir = "${project.buildDir}/new_golden_images"
def goldensDir =
"${javaTestDir}/google/registry/webdriver/goldens/chrome-linux"
def jsDir = "${project.projectDir}/src/main/javascript"
// Tests that fail when running Gradle in a docker container, e. g. when
// building the release artifacts in Google Cloud Build.

View File

@@ -1,94 +0,0 @@
/**
* @fileoverview Provides Soy runtime checks for safe types.
*
* NOTE (gbrodman) this file is taken from the open source version located at
* https://github.com/google/closure-templates/blob/6c8cf1c7916abd0ab5d7e9d259985873f8af4fd2/javascript/checks.js
*/
goog.provide('soy.checks');
goog.require('goog.asserts');
goog.require('goog.soy.data.SanitizedContentKind');
goog.require('goog.soy.data.SanitizedCss');
goog.require('goog.soy.data.SanitizedHtml');
goog.require('goog.soy.data.SanitizedHtmlAttribute');
goog.require('goog.soy.data.SanitizedJs');
goog.require('goog.soy.data.SanitizedTrustedResourceUri');
goog.require('goog.soy.data.SanitizedUri');
/**
* Checks whether a given value is of a given content kind.
*
* @param {?} value The value to be examined.
* @param {!goog.soy.data.SanitizedContentKind} contentKind The desired content
* kind.
* @param {!Object} constructor
* @return {boolean} Whether the given value is of the given kind.
* @private
*/
soy.checks.isContentKind_ = function(value, contentKind, constructor) {
var ret = value != null && value.contentKind === contentKind;
if (ret) {
goog.asserts.assert(value.constructor === constructor);
}
return ret;
};
/**
* @param {?} value
* @return {boolean}
*/
soy.checks.isHtml = function(value) {
return soy.checks.isContentKind_(
value, goog.soy.data.SanitizedContentKind.HTML,
goog.soy.data.SanitizedHtml);
};
/**
* @param {?} value
* @return {boolean}
*/
soy.checks.isCss = function(value) {
return soy.checks.isContentKind_(
value, goog.soy.data.SanitizedContentKind.CSS,
goog.soy.data.SanitizedCss);
};
/**
* @param {?} value
* @return {boolean}
*/
soy.checks.isAttribute = function(value) {
return soy.checks.isContentKind_(
value, goog.soy.data.SanitizedContentKind.ATTRIBUTES,
goog.soy.data.SanitizedHtmlAttribute);
};
/**
* @param {?} value
* @return {boolean}
*/
soy.checks.isJS = function(value) {
return soy.checks.isContentKind_(
value, goog.soy.data.SanitizedContentKind.JS, goog.soy.data.SanitizedJs);
};
/**
* @param {?} value
* @return {boolean}
*/
soy.checks.isTrustedResourceURI = function(value) {
return soy.checks.isContentKind_(
value, goog.soy.data.SanitizedContentKind.TRUSTED_RESOURCE_URI,
goog.soy.data.SanitizedTrustedResourceUri);
};
/**
* @param {?} value
* @return {boolean}
*/
soy.checks.isURI = function(value) {
return soy.checks.isContentKind_(
value, goog.soy.data.SanitizedContentKind.URI,
goog.soy.data.SanitizedUri);
};

View File

@@ -1,24 +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.
/**
* @fileoverview Test existing solely to run the :check BUILD rule.
*/
goog.setTestOnly();
goog.require('goog.testing.jsunit');
function testNothing() {}

View File

@@ -1,84 +0,0 @@
/** Admin Settings */
div#tlds div.tld {
width: 209px;
}
#newTld {
width: 187px;
margin-left: 0.5em;
}
div#tlds div.tld input,
div#tlds div.tld button[type=button] {
height: 27px;
line-height: 27px;
background: #ebebeb;
vertical-align: top;
border: none;
border-bottom: solid 3px white;
}
div#tlds div.tld input {
width: 169px;
margin: 0;
padding: 0;
color: #555;
padding-left: 5px ! important;
}
div#tlds.editing div.tld input[readonly] {
margin-left: 0.5em;
}
div#tlds.editing div.tld button[type=button] {
display: inline-block;
float: right;
margin-left: -2px;
width: 30px;
min-width: 30px;
height: 30px;
color: grey;
font-size: 1.1em;
}
div#tlds.editing div.tld button[type=button]:hover {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
div#tlds.editing div.tld button[type=button] i {
font-style: normal;
}
div#tlds.editing .kd-errormessage {
margin-left: 0.5em;
}
#ote-results-table {
margin-left: 0.5em;
margin-top: -5px;
border-top: 0;
padding-top: 0;
}
.ote-fulfilled {
background-color: #9df797;
}
.ote-semifulfilled {
background-color: #fcd18e;
}
.ote-unfulfilled {
background-color: #ffa9a9;
}
.ote-results-header {
height: 20px;
}
.ote-results-header-cell {
vertical-align: bottom;
}

View File

@@ -1,81 +0,0 @@
.description {
display: block;
clear: both;
font-size: 12px;
color: #999;
line-height: 140%;
}
a:hover, a:focus {
text-decoration: underline
}
.whoAreYou {
width: 50%;
margin: 5em auto;
}
/* Console disabled page. */
.whoAreYou-disabled {
width: 50%;
margin: 5em auto;
}
.whoAreYou-disabled p img {
display: block;
margin: 3em auto;
}
.whoAreYou-disabled h1 {
border-top: solid 1px #ebebeb;
margin-top: 1em;
}
/* XXX: Should be re-enabled when search works. */
#kd-search {
display: none;
}
/* XXX: Should be generalized for use throughout console. */
div.domain-registrar-contact div.tooltip {
visibility: hidden;
/* XXX: Should have auto-width. */
width: 110px;
left: -55px;
height: 1em;
white-space: nowrap;
position: relative;
color: white;
background: #2d2d2d;
padding: 0.5em;
z-index: 2000;
margin-top: -30px;
font-style: normal;
}
div.domain-registrar-contact div.tooltip .pointer {
outline: none;
display: block;
position: relative;
bottom: -7px;
left: 55px;
margin: 0 0 0 -5px;
width: 0;
height: 0;
line-height: 0px;
font-size: 0px;
/* This sets the tooptip pointer color */
border-bottom: transparent;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #2d2d2d;
}
.reg-cryingAndroid {
float: right;
}
.reg-bullets {
padding-left: 1em;
list-style: disc inside;
}

View File

@@ -1,58 +0,0 @@
.domain-registrar-contacts {
vertical-align: top;
text-align: top;
}
.domain-registrar-contact {
display: table-cell;
padding-right: 4em;
padding-bottom: 2em;
}
.domain-registrar-contact div {
margin: 0.5em 0;
}
.domain-registrar-contact + br {
display: table-row;
}
.domain-registrar-contact-name {
font-weight: bold;
display: inline;
padding-right: 30px;
}
.domain-registrar-contact-name i {
float: right;
width: 16px;
height: 16px;
}
.domain-registrar-contact-name i.domain-registrar-contact-visible-in-whois {
background: url('/assets/images/visibleOn_16.png') no-repeat right;
}
/** Postal style for address. */
td.setting-group-compact div.contact-address-city,
td.setting-group-compact div.contact-address-state,
td.setting-group-compact div.contact-address-zip,
td.setting-group-compact div.contact-address-cc {
width: initial;
display: inline;
}
/** Back to regular box flow for phone. */
td.setting-group-compact input#phoneNumber {
clear: both;
}
/**
* Vertical align shim for contact tds. Using border here instead of
* padding since this is a table and padding is ignored.
*
* @see td.setting p
*/
td.domain-registrar-contacts {
border-top: solid 0.5em white;
}

View File

@@ -1,16 +0,0 @@
#domain-registrar-contact-us .description * {
color: #999 !important;
line-height: 140%;
}
#domain-registrar-contact-us p {
margin-bottom: 1.5em;
line-height: 140%;
}
#registry-phone {
width: 100%;
margin: 0;
padding: 1em;
background-color: #eaeaea;
}

View File

@@ -1,63 +0,0 @@
#domain-registrar-dashboard {
text-align: center;
}
#domain-registrar-dashboard p {
color: grey;
}
#domain-registrar-dashboard super {
color: red;
font-size: 0.5em;
vertical-align: super;
font-weight: bold;
padding-left: 0.5em;
}
#domain-registrar-dashboard table {
border-collapse: collapse;
margin: 3em auto;
}
#domain-registrar-dashboard div.dashbox {
width: 230px;
min-width: 230px;
height: 260px;
padding: 1em 2em;
margin: 0 1.5em;
color: #777;
border-radius: 10px;
background-color: #f9f9f9;
text-align: center;
line-height: 140%;
font-size: 1.1em;
}
#domain-registrar-dashboard div.dashbox h2 {
font-weight: bold;
color: #555;
margin: 2em auto 1em auto;
}
#domain-registrar-dashboard div.dashbox a {
color: inherit;
}
#domain-registrar-dashboard table img {
display: block;
margin: 1em auto;
padding: 1em auto;
}
#domain-registrar-dashboard table + p {
margin: 2em auto;
width: 75%;
vertical-align: middle;
text-align: center;
}
#domain-registrar-dashboard p img {
margin-right: 1em;
vertical-align: middle;
text-align: center;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,61 +0,0 @@
/* EPP styles */
.reg-add:before {
content: '+ ';
}
.contact h1 {
width: 650px;
background: url('/assets/images/ic_contacts_blue_12.png') no-repeat 0 0.7em;
padding-left: 2em;
margin-left: 0.75em;
}
/* Remove button. */
#contact-postalInfo table button {
margin: 1em;
float: right;
}
#contact-postalInfoHeader {
color: #777;
font-weight: normal;
}
#contact-postalInfo .info {
font-size: 11px;
color: #666;
}
#contact-postalInfo table {
margin: 0 0 1em 0;
padding: 1em;
}
#contact-postalInfo tr {
margin: auto 2em;
}
#contact-postalInfo tr:first-child {
margin-top: 1em;
}
#contact-postalInfo tr:last-child {
margin-bottom: 1em;
}
#contact-postalInfo table,
#contact-postalInfo input[readonly],
#contact-postalInfo textarea[readonly] {
background-color: #f1f1f1;
border-color: #f1f1f1;
}
#contact-postalInfoHeader button {
display: block;
margin: 1em 0;
}
#contact-postalInfoHeader button[disabled] {
display: none;
}

View File

@@ -1,187 +0,0 @@
form.set,
form.item,
div.set,
div.item {
width: 700px;
}
.set table,
.item table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
}
/* Going to play some games here to get section leads to float left,
* followed by their next rows in floated right column. */
.item table,
.set table {
padding-top: 2em;
margin-top: 1em;
border-top: solid 1px #ebebeb;
}
.set tr,
.item tr {
margin: 0;
padding: 0;
min-height: 28px;
}
.set td,
.item td {
padding: 0.5em 0;
}
.item tr.section-lead th h2,
.item tr.section-lead th h3 {
font-size: 1em;
font-weight: bold;
color: #15c;
}
tr.subsection h3::first-letter {
text-transform: capitalize;
}
.set td:first-child,
.item td:first-child {
width: 260px;
}
.set td:first-child span.description,
.item td:first-child span.description {
width: 170px;
}
.description ol {
list-style-type: decimal;
margin-left: 2em;
}
/* Setting groups and labels. */
.set .kd-settings-pane-section td {
border-bottom: solid 1px #ebebeb;
}
td.setting-group-compact {
padding-left: 0.5em;
}
.setting-group-compact div {
line-height: 140%;
}
.item label {
font-weight: bold;
}
.set label + input {
margin-left: 1em;
}
.kd-settings-pane-section td label.setting-label {
padding-top: 0.5em;
}
td.label {
width: 70%;
}
/* Compact sequence of labels. */
.setting label + label {
margin-left: 2em;
}
form label,
.setting-label {
line-height: 13px;
margin-bottom: 5px;
}
.setting label {
display: inline-block;
font-weight: normal;
margin-right: 1em;
vertical-align: top;
}
div.checkbox-with-label {
margin-bottom: 1em;
}
/* Controls */
.set input:not([type="submit"]),
.item input:not([type="submit"]) {
width: 250px;
padding: 0.5em;
}
.item input[type='checkbox'],
.item input[type='radio'] {
width: auto;
}
input[readonly] {
border: solid 1px white;
margin-left: 0.5em;
padding-top: 0 !important;
padding-left: 0 !important;
}
.setting input[type=radio] {
}
.setting input[type=radio],
.setting input[type=checkbox] {
position: relative;
top: -3px;
}
/**
* Consistent top space in second column items. Input elements need to
* switch from using margin to padding when they're edit toggled, so that
* the text doesn't move. The other elements are just defined here for
* consistency.
* @see td.domain-registrar-contacts
*/
input[readonly],
td.setting p {
margin-top: 0.5em;
margin-left: 0.5em;
}
.item button[disabled] {
display: none;
}
div.checkbox-with-label input[type='checkbox'],
div.checkbox-with-label input[type='checkbox'] + label {
display: inline-block;
}
/*
* 3 line street has just inputs in a row
* @see td padding-bottom
*/
.setting input + input,
.setting div {
margin-top: 1em;
}
.setting div {
margin-top: 0.5em;
}
.setting input[type='checkbox'] {
display: inline;
}
.setting input + button,
.setting-item-list {
margin-left: 0.5em;
}

View File

@@ -1,11 +0,0 @@
@import 'admin-settings.css';
@import 'console.css';
@import 'contact-settings.css';
@import 'contact-us.css';
@import 'dashboard.css';
@import 'epp.css';
@import 'forms.css';
@import 'kd_components.css';
@import 'registry.css';
@import 'resources.css';
@import 'security-settings.css';

View File

@@ -1,85 +0,0 @@
/** 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
}
/** Following section taken from https://loading.io/css, under CC0 licensing. */
.lds-ring {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 64px;
height: 64px;
margin: 8px;
border: 8px solid #000000;
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #000000 transparent transparent transparent;
}
.lds-ring div:nth-child(1) {
animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/** End of material taken from https://loading.io/css. */

View File

@@ -1,326 +0,0 @@
body {
overflow-x: hidden;
overflow-y: hidden !important;
font-family: Arial, sans-serif;
font-size: 13px;
color: #222;
}
h1 {
width: 100%;
font-size: 1.5em;
/* Bottom padding to get the paragraph text and Billing & resources to
* line up. */
padding: 0.75em 0.75em 3px 0;
}
#kd-social a,
#kd-social a:visited,
#reg-content a,
#reg-content a:visited {
color: #15c;
}
pre {
font-family: "Courier New", Courier, monospace;
white-space: pre-wrap;
}
table {
table-layout: fixed;
}
td {
vertical-align: top;
}
/* Set some explicit form styles so there's no jumping during toggle
* from readonly to editable. */
input, textarea {
border-style: solid;
border-color: lightgrey;
border-width: 1px;
}
input[readonly], textarea[readonly] {
resize: none;
border-color: white;
}
textarea {
margin-bottom: 1em;
font-family: "Courier New", Courier, monospace;
font-size: 13px;
border: solid 1px #ddd;
}
textarea[readonly] {
background-color: #eaeaea;
}
hr {
border: none;
border-top: solid 1px #ebebeb;
}
.hidden {
display: none;
}
#kd-googlebar {
position: fixed;
width: 100%;
min-width: 985px;
padding: 1em 2em;
white-space: nowrap;
height: 37px;
}
#kd-googlebar a.logo,
#kd-searchfield,
#kd-searchbutton {
position: static;
display: inline-block;
}
#kd-search {
width: 470px;
margin-top: 2px;
padding-top: 0px;
padding-left: 3em;
white-space: nowrap;
}
#kd-search form {
width: auto;
}
input#kd-searchfield,
#kd-searchbutton {
height: 29px;
border: none;
}
input#kd-searchfield {
width: 400px;
font-size: 12pt;
}
#kd-searchbutton {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
#kd-social {
position: fixed;
top: 1.25em;
right: 0;
}
#kd-social .kd-name {
float: none;
color: #555;
}
.kd-name a:before {
content: ' | ';
color: #999;
}
/* Logo */
a.logo {
vertical-align: middle;
font-size: 30px;
font-weight: 300;
font-family: "open sans", sans-serif;
color: #63666a;
}
a.logo * {
vertical-align: middle;
}
/* Reg prefix. */
.reg-user-id {
display: block;
height: 1.5em;
padding: 0;
margin-top: -10px;
}
/* Misc. */
#loady {
position: absolute;
top: 5px;
right: -30px;
}
.eppResponse {
color: #333;
margin-top: 1em;
}
.kd-appbar {
padding: 1em 0;
position: fixed;
width: 100%;
}
li.kd-menulistitem {
text-transform: none;
}
#reg-nav.shown {
display: inherit;
}
/* Begin fixed headers and nav selectors */
#reg-app {
float: left;
margin-top: 64px;
width: 100%;
}
.kd-butterbar {
position: absolute;
display: block;
margin-left: inherit;
}
.kd-butterbar.shown {
-webkit-transform: translateX(-50%);
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
.kd-appbar {
/* same as in reg-content below. lines the left edge of the
appbuttons and content area with the 'r' in registry. */
padding-left: 173px;
padding-top: .75em;
}
.kd-content-sidebar {
margin-left: 15px;
padding-left: 0;
border-left: 0;
}
#reg-nav {
position: fixed;
left: 0;
top: 136px;
width: 155px;
margin: 0 25px 0 0;
z-index: 3;
}
#reg-navlist li {
margin-left: 0;
padding-left: 0;
}
#reg-navlist li ul {
margin-left: 0em;
padding-left: 2em;
}
.reg-navlist-sub {
padding-left: 3px;
}
#reg-navlist a {
margin-left: 0;
padding-left: 2em;
border-left: solid 3px white;
}
#reg-navlist li ul,
#reg-navlist a {
line-height: 24px;
}
#reg-navlist li ul li {
margin-left: -2em;
}
#reg-navlist li ul li a {
padding-left: 3em;
}
#reg-navlist a.domain-active-nav {
border-left: solid 3px red;
font-weight: bold;
color: #bf624B;
}
#reg-content-and-footer {
position: absolute;
top: 136px;
left: 173px;
bottom: 0;
width: calc(100% - 173px);
margin: 0;
padding: 25px 0 1em 0;
overflow-y: scroll !important;
overflow-x: hidden;
}
#reg-content {
margin-bottom: 100px;
}
#reg-content,
.pageFooter {
width: 75%;
}
#debug {
position: absolute;
top: 127px;
right: 0;
width: 15%;
border-left: solid 1px grey;
padding-left: 1em;
}
/* End fixed headers and nav selectors */
#reg-content,
#reg-login {
min-height: 400px;
}
.reg-select {
margin-left: 23px;
}
div#reg-deprecation-warning {
position: fixed;
top: 64px;
width: 100%;
left: 0;
text-align: center;
background-color: #ba2a1a;
font-size: 0.6svw;
}
div#reg-deprecation-warning h1 {
color: #ffffff;
}
div#reg-deprecation-warning a {
color: #add8e6;
}
div#reg-accessing-as-role {
margin-top: 40px;
}
@media screen and (max-width: 1600px) {
div#reg-deprecation-warning {
font-size: 0.85vw;
}
}

View File

@@ -1,28 +0,0 @@
#domain-registrar-resources h2 {
border-top: solid 1px #eee;
padding-top: 1em;
margin-top: 1em;
}
#domain-registrar-resources h2 img {
vertical-align: middle;
margin-right: 10px;
}
#domain-registrar-resources h2 + p,
#domain-registrar-resources button,
#domain-registrar-resources em {
margin-left: 34px; /* Folder icon + ^^ 10px more */
}
#domain-registrar-resources h2 + p {
padding-top: 1em;
}
#domain-registrar-resources a {
color: white !important;
}
#domain-registrar-resources em {
color: red;
}

View File

@@ -1,67 +0,0 @@
/** Security Settings */
#domain-registrar-phone-passcode,
#domain-registrar-phone-passcode input {
color: #3D9200;
}
div#ips div.ip {
width: 209px;
}
#newIp {
width: 187px;
margin-left: 0.5em;
}
div#ips.editing div.ip input,
div#ips.editing div.ip button[type=button] {
display: inline-block;
height: 27px;
line-height: 27px;
background: #ebebeb;
vertical-align: top;
border: none;
border-bottom: solid 3px white;
}
div#ips.editing div.ip input {
width: 169px;
margin: 0;
padding: 0;
color: #555;
padding-left: 5px ! important;
}
div#ips.editing div.ip input[readonly] {
margin-left: 0.5em;
}
div#ips.editing div.ip button[type=button] {
float: right;
margin-left: -2px;
width: 30px;
min-width: 30px;
height: 30px;
color: grey;
font-size: 1.1em;
}
div#ips.editing div.ip button[type=button]:hover {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
div#ips.editing div.ip button[type=button] i {
font-style: normal;
}
div#ips.editing .kd-errormessage {
margin-left: 0.5em;
}
.item td.certificate h4 {
margin-top: 1em;
text-transform: lowercase;
border: solid 1px red;
}

View File

@@ -1,187 +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.
/**
* @fileoverview External JSON definitions. The purpose of this file is to give
* type information to the JavaScript compiler so it won't rename these
* properties.
* @externs
*/
/**
* @suppress {duplicate}
*/
var registry = {};
/**
* @suppress {duplicate}
*/
registry.json = {};
registry.json.locks = {};
/**
* @typedef {{
* domainName: string,
* lockedTime: string,
* lockedBy: string,
* userCanUnlock: boolean,
* isLockPending: boolean,
* isUnlockPending: 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 = {};
/**
* @typedef {{
* description: string,
* requirement: number,
* timesPerformed: number,
* completed: boolean
* }}
*/
registry.json.ote.OteStatusDetail;
/**
* @typedef {{
* clientId: string,
* completed: boolean,
* details: !Array.<registry.json.ote.OteStatusDetail>
* }}
*/
registry.json.ote.OteStatusResult;
/**
* @typedef {{
* status: string,
* message: string,
* results: !Array.<registry.json.ote.OteStatusResult>
* }}
*/
registry.json.ote.OteStatusResponse;
/**
* @constructor
* @template T
*/
registry.json.Response = function() {};
/**
* Request state which can be `SUCCESS` or `ERROR`.
* @type {string}
*/
registry.json.Response.prototype.status;
/**
* @type {string}
*/
registry.json.Response.prototype.message;
/**
* @type {string|undefined}
*/
registry.json.Response.prototype.field;
/**
* @type {!Array.<T>}
*/
registry.json.Response.prototype.results;
// XXX: Might not need undefineds here.
/**
* @typedef {{
* allowedTlds: !Array<string>,
* registrarId: string,
* clientCertificate: string?,
* clientCertificateHash: string?,
* failoverClientCertificate: string?,
* failoverClientCertificateHash: string?,
* driveFolderId: string?,
* ianaIdentifier: (number?|undefined),
* icannReferralEmail: string,
* ipAddressAllowList: !Array<string>,
* emailAddress: (string?|undefined),
* lastUpdateTime: string,
* url: (string?|undefined),
* phonePasscode: (string?|undefined),
* phoneNumber: (string?|undefined),
* faxNumber: (string?|undefined),
* localizedAddress: registry.json.RegistrarAddress,
* whoisServer: (string?|undefined),
* referralUrl: (string?|undefined),
* contacts: !Array.<registry.json.RegistrarContact>,
* registryLockAllowed: boolean
* }}
*/
registry.json.Registrar;
/**
* @typedef {{
* street: !Array.<string>,
* city: string,
* state: (string?|undefined),
* zip: (string?|undefined),
* countryCode: string
* }}
*/
registry.json.RegistrarAddress;
/**
* @typedef {{
* name: (string?|undefined),
* emailAddress: string,
* visibleInWhoisAsAdmin: boolean,
* visibleInWhoisAsTech: boolean,
* visibleInDomainWhoisAsAbuse: boolean,
* phoneNumber: (string?|undefined),
* faxNumber: (string?|undefined),
* types: (string?|undefined),
* allowedToSetRegistryLockPassword: boolean,
* registryLockAllowed: boolean,
* registryLockEmailAddress: (string?|undefined)
* }}
*/
registry.json.RegistrarContact;

View File

@@ -1,79 +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.Component');
goog.forwardDeclare('registry.Console');
goog.require('goog.events.EventHandler');
goog.require('registry.util');
/**
* Base component for UI.
*
* <pre>
* ui/js/component.js - Base UI class.
* ^
* |
* edit_item.js - Common controls for editable items.
* ^
* \
* |-ui/js/resource_component.js - JSON resources
* ^
* \
* |- ui/js/registrar/settings.js
* </pre>
*
* @param {!registry.Console} cons the console singleton.
* @constructor
* @extends {goog.events.EventHandler}
*/
registry.Component = function(cons) {
registry.Component.base(this, 'constructor');
/** @type {!registry.Console} */
this.console = cons;
/**
* The hashPath this component is mapped by. This is set by the
* console after construction.
* @type {string}
*/
this.basePath = '';
/**
* Bean counter that's used by `addRemBtnHandlers`,
* e.g. `typeCounts['host']++` when user adds or removes.
* @type {!Object.<string, number>}
* @protected
*/
this.typeCounts = {};
/**
* Stateful UI/server session model.
* @type {?Object.<string, ?>}
*/
this.model = null;
};
goog.inherits(registry.Component, goog.events.EventHandler);
/**
* Subclasses should override this to implement panel display.
* @param {string} id The target resource id.
*/
registry.Component.prototype.bindToDom = function(id) {
registry.util.unbutter();
};

View File

@@ -1,144 +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.Console');
goog.require('goog.Disposable');
goog.require('goog.History');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('goog.history.EventType');
goog.require('registry.util');
goog.forwardDeclare('goog.events.KeyEvent');
/**
* Abstract console for both admin and registrar console UIs.
* @constructor
* @extends {goog.Disposable}
*/
registry.Console = function() {
registry.Console.base(this, 'constructor');
/**
* @type {!goog.History}
* @protected
*/
this.history = new goog.History();
};
goog.inherits(registry.Console, goog.Disposable);
/**
* Registers the console's events and sets everything up.
*
* Should be called after the constructor.
*
* The reason this isn't done in the constructor is that this is a base class
* designed to be extended. We have to wait for the actual implementation to
* finish constructing before using it.
*/
registry.Console.prototype.setUp = function() {
goog.events.listen(
this.history,
goog.history.EventType.NAVIGATE,
goog.bind(this.handleHashChange, this));
this.bindToDom();
// goog.History always starts off as "not enabled", meaning it doesn't trigger
// the listeners on change.
//
// When it's set to be enabled, it will start triggering the listeners on
// every change, but it also triggers the listeners immediately with the
// current history entry.
//
// This means the handleHashChange listener registered above will be called
// now.
this.history.setEnabled(true);
};
/**
* Helper to setup permanent page elements.
*/
registry.Console.prototype.bindToDom = function() {
registry.util.unbutter();
goog.events.listen(goog.dom.getRequiredElement('kd-searchbutton'),
goog.events.EventType.CLICK,
goog.bind(this.onSearch_, this));
goog.events.listen(goog.dom.getRequiredElement('kd-searchfield'),
goog.events.EventType.KEYUP,
goog.bind(this.onSearchFieldKeyUp_, this));
goog.events.listen(
goog.dom.getElementByClass(goog.getCssName('kd-butterbar-dismiss')),
goog.events.EventType.CLICK,
registry.util.unbutter);
};
/**
* Subclasses should override to visit the hash token given by
* `goog.History.getToken()`.
*/
registry.Console.prototype.handleHashChange = goog.abstractMethod;
/**
* @param {string} resourcePath Resource description path.
*/
registry.Console.prototype.view = function(resourcePath) {
// Setting the new history token will also trigger the handleHashChange
// listener registered in the setUp() function.
this.history.setToken(resourcePath);
};
/**
* Handler for search bar.
* @private
*/
registry.Console.prototype.onSearch_ = function() {
var qElt = goog.dom.getRequiredElement('kd-searchfield');
if (qElt.getAttribute('disabled')) {
return;
}
var query = qElt.value;
if (query == '') {
return;
}
// Filtering this value change event.
qElt.setAttribute('disabled', true);
qElt.value = '';
this.view(query);
qElt.removeAttribute('disabled');
};
/**
* Handler for key press in the search input field.
* @param {!goog.events.KeyEvent} e Key event to handle.
* @return {boolean} Whether the event should be continued or cancelled.
* @private
*/
registry.Console.prototype.onSearchFieldKeyUp_ = function(e) {
if (e.keyCode == goog.events.KeyCodes.ENTER) {
this.onSearch_();
return false;
}
return true;
};

View File

@@ -1,315 +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.EditItem');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.soy');
goog.require('registry.Component');
goog.require('registry.soy.console');
goog.require('registry.util');
goog.forwardDeclare('registry.Console');
/**
* An editable item, with Edit and Save/Cancel buttons in the appbar.
* @param {!registry.Console} cons
* @param {function()} itemTmpl
* @param {boolean} isEditable
* @constructor
* @extends {registry.Component}
*/
registry.EditItem = function(cons, itemTmpl, isEditable) {
registry.EditItem.base(this, 'constructor', cons);
/**
* @type {!Function}
*/
this.itemTmpl = itemTmpl;
/**
* Optional current target resource id.
* @type {?string}
*/
this.id = null;
/**
* Should the "edit" button be enabled?
* @type {boolean}
*/
this.isEditable = isEditable;
/**
* Transitional id for next resource during create.
* @type {?string}
*/
this.nextId = null;
};
goog.inherits(registry.EditItem, registry.Component);
/** @override */
registry.EditItem.prototype.bindToDom = function(id) {
registry.EditItem.base(this, 'bindToDom', id);
this.id = id;
this.nextId = null;
this.setupAppbar();
};
/** Setup appbar save/edit buttons. */
registry.EditItem.prototype.setupAppbar = function() {
goog.soy.renderElement(goog.dom.getRequiredElement('reg-app-buttons'),
registry.soy.console.appbarButtons);
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-add'),
goog.events.EventType.CLICK,
goog.bind(this.add, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-edit'),
goog.events.EventType.CLICK,
goog.bind(this.edit, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-save'),
goog.events.EventType.CLICK,
goog.bind(this.save, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-cancel'),
goog.events.EventType.CLICK,
goog.bind(this.cancel, this));
goog.events.listen(goog.dom.getRequiredElement('reg-app-btn-back'),
goog.events.EventType.CLICK,
goog.bind(this.back, this));
// Show the add/edit buttons only if isEditable.
// "edit" is shown if we have an item's ID
// "add" is shown if we don't have an item's ID
registry.util.setVisible('reg-app-btns-edit', this.isEditable && !!this.id);
registry.util.setVisible('reg-app-btn-add', this.isEditable && !this.id);
};
/**
* Retrieve item from server. Overrides should callback to
* `#handleFetchItem(string, !Object)`.
* @param {string} id item id.
*/
registry.EditItem.prototype.fetchItem = goog.abstractMethod;
/**
* Handle result decoding and display.
* @param {string} id The requested ID/name, for error message.
* @param {!Object} rsp The requested object.
*/
registry.EditItem.prototype.handleFetchItem = goog.abstractMethod;
/** Subclasses should override to continue processing after fetch. */
registry.EditItem.prototype.processItem = function() {};
/**
* Show the item.
* @param {!Object} objArgs
*/
registry.EditItem.prototype.renderItem = function(objArgs) {
goog.soy.renderElement(goog.dom.getRequiredElement('reg-content'),
this.itemTmpl,
objArgs);
this.runAfterRender(objArgs);
};
/**
* @return {boolean} if the component is currently being edited.
*/
registry.EditItem.prototype.isEditing = function() {
return goog.dom.classlist.contains(
goog.dom.getElement('reg-app'), goog.getCssName('editing'));
};
/**
* Toggles the editing state of a component. This will first hide the
* elements of the `shown` class, then adds the `editing`
* style to the component, then shows the elements that had the `hidden`
* class.
*/
registry.EditItem.prototype.toggleEdit = function() {
// Toggle appbar buttons.
var addBtn = goog.dom.getRequiredElement('reg-app-btn-add');
var editBtns = goog.dom.getRequiredElement('reg-app-btns-edit');
var saveBtns = goog.dom.getRequiredElement('reg-app-btns-save');
var editing = goog.dom.classlist.contains(saveBtns,
registry.util.cssShown);
if (editing) {
registry.util.setVisible(saveBtns, false);
if (this.id) {
registry.util.setVisible(editBtns, true);
} else {
registry.util.setVisible(addBtn, true);
}
} else {
if (this.id) {
registry.util.setVisible(editBtns, false);
} else {
registry.util.setVisible(addBtn, false);
}
registry.util.setVisible(saveBtns, true);
}
// Then page contents.
var parentElt = goog.dom.getElement('reg-content');
var shownCssName = goog.getCssName('shown');
var hiddenCssName = goog.getCssName('hidden');
var shown = goog.dom.getElementsByClass(shownCssName, parentElt);
var hidden = goog.dom.getElementsByClass(hiddenCssName, parentElt);
for (var i = 0; i < shown.length; i++) {
goog.dom.classlist.addRemove(shown[i], shownCssName, hiddenCssName);
}
// Then add editing styles.
var editingCssName = goog.getCssName('editing');
var startingEdit = !goog.dom.classlist.contains(parentElt, editingCssName);
if (startingEdit) {
goog.dom.classlist.remove(parentElt, editingCssName);
} else {
goog.dom.classlist.add(parentElt, editingCssName);
}
// The show hiddens.
for (var i = 0; i < hidden.length; i++) {
goog.dom.classlist.addRemove(hidden[i], hiddenCssName, shownCssName);
}
};
/**
* Subclasses should override to enhance the default model.
* @return {!Object.<string, ?>}
*/
registry.EditItem.prototype.newModel = function() {
return {item: {}};
};
// N.B. setting these as abstract precludes their correct binding in
// setupAppbar.
/** Show add item panel. */
registry.EditItem.prototype.add = function() {};
/** Go back from item to collection view. */
registry.EditItem.prototype.back = function() {};
/** Sets up initial edit model state and then called edit(objArgs). */
registry.EditItem.prototype.edit = function() {
var objArgs = this.model;
if (objArgs == null) {
objArgs = this.newModel();
}
// XXX: This is vestigial. In the new msg format, this pollutes the
// server-model state. Should be carried elsewhere.
objArgs.readonly = false;
this.renderItem(objArgs);
this.setupEditor(objArgs);
this.toggleEdit();
};
/**
* Save the current item. Calls either create if creating a new
* object or update otherwise.
*/
registry.EditItem.prototype.save = function() {
if (this.model == null) {
this.sendCreate();
} else {
this.sendUpdate();
}
};
/**
* Resets to non-editing, readonly state, or visits home screen if the
* page was in on a create panel.
*/
registry.EditItem.prototype.cancel = function() {
this.toggleEdit();
// XXX: The presence of a model is sufficient for non-collection pages, but an
// empty id also means go to the collection in collection pages. Should
// be simplified.
if (this.model && this.id != '') {
this.model.readonly = true;
this.renderItem(this.model);
} else {
this.bindToDom('');
}
};
/**
* 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
// breaks this opportunity. Hmmm...
/** Subclasses should extract form values and send them to the server. */
registry.EditItem.prototype.sendCreate = goog.abstractMethod;
/** Subclasses should extract form values and send them to the server. */
registry.EditItem.prototype.sendUpdate = goog.abstractMethod;
/** Subclasses should extract form values and send them to the server. */
registry.EditItem.prototype.sendDelete = goog.abstractMethod;
/**
* Subclasses should override to populate update queryParams with form
* fields as needed. `queryParams.nextId` MUST be set to the
* new object's ID.
* @param {!Object} queryParams
*/
registry.EditItem.prototype.prepareUpdate = goog.abstractMethod;
/**
* Subclasses should provide a function to parse JSON response from server and
* return a result object as described below.
* @param {!Object} rsp Decoded JSON response from the server.
* @return {!Object} a result object describing next steps. On
* success, if next is defined, visit(ret.next) is called, otherwise
* if err is set, the butterbar message is set to it.
*/
registry.EditItem.prototype.handleUpdateResponse = goog.abstractMethod;

View File

@@ -1,137 +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.forms');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.dom.forms');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('registry.util');
goog.forwardDeclare('goog.events.KeyEvent');
/**
* Sets the focus on a form field (if it exists).
* @param {Element|string} field Form field (or ID) to focus.
*/
registry.forms.focus = function(field) {
field = goog.dom.getElement(field);
if (field !== null && goog.dom.isFocusable(field)) {
goog.dom.forms.focusAndSelect(field);
}
};
/**
* Displays a form field error, or butters if no field is specified.
* @param {string} message Human-readable explanation of why this field is evil.
* @param {string=} opt_field Erroneous field name.
*/
registry.forms.displayError = function(message, opt_field) {
if (opt_field === undefined) {
registry.util.butter(message);
return;
}
var input = goog.dom.getElement(opt_field) ||
goog.dom.getElement(opt_field + '[0]');
// XXX: Transitioning to use of form.eltId instead of DOM id. If DOM id
// lookup fails, then search forms for the named field.
if (opt_field != null && input === null) {
for (var fNdx in document.forms) {
var form = document.forms[fNdx];
if (form[opt_field]) {
input = form[opt_field];
break;
}
}
}
if (input !== null) {
goog.dom.classlist.add(input, goog.getCssName('kd-formerror'));
goog.dom.insertSiblingAfter(
goog.dom.createDom(goog.dom.TagName.DIV,
goog.getCssName('kd-errormessage'),
message),
input);
registry.forms.focus(input);
} else {
registry.util.butter(opt_field + ': ' + message);
}
};
/** Removes error markup from whois settings form. */
registry.forms.resetErrors = function() {
registry.util.unbutter();
goog.array.forEach(
goog.dom.getElementsByClass(goog.getCssName('kd-formerror')),
function(field) {
goog.dom.classlist.remove(field, goog.getCssName('kd-formerror'));
});
goog.array.forEach(
goog.dom.getElementsByClass(goog.getCssName('kd-errormessage')),
goog.dom.removeNode);
};
/**
* Adds enter key listeners to all form fields.
* @param {!Element} container Parent element containing INPUT fields.
* @param {function()} callback Called when enter is pressed in a field.
*/
registry.forms.listenFieldsOnEnter = function(container, callback) {
var handler = goog.partial(registry.forms.onFieldKeyUp_, callback);
goog.array.forEach(
goog.dom.getElementsByTagNameAndClass(
goog.dom.TagName.INPUT, undefined, container),
function(field) {
goog.events.listen(field, goog.events.EventType.KEYUP, handler);
});
};
/**
* Event handler that saves form when enter is pressed in a form field.
* @param {function()} callback Called when key pressed is ENTER.
* @param {!goog.events.KeyEvent} e Key event to handle.
* @return {boolean} Whether the event should be continued or cancelled.
* @private
*/
registry.forms.onFieldKeyUp_ = function(callback, e) {
if (e.keyCode == goog.events.KeyCodes.ENTER) {
callback();
return false;
}
return true;
};
/**
* Toggles disabled state of a button or form element.
* @param {!Element} element Form element to disable.
* @param {boolean} enabled Enables element if true, or else disables it.
*/
registry.forms.setEnabled = function(element, enabled) {
if (enabled) {
goog.dom.classlist.remove(element, goog.getCssName('disabled'));
} else {
goog.dom.classlist.add(element, goog.getCssName('disabled'));
element.blur();
}
};

View File

@@ -1,137 +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.MenuButton');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventType');
goog.forwardDeclare('goog.events.BrowserEvent');
/**
* Kennedy style menu button.
* @param {!Element} button Menu button element.
* @constructor
* @extends {goog.events.EventHandler}
* @final
*/
registry.MenuButton = function(button) {
registry.MenuButton.base(this, 'constructor');
/**
* Outer menu button element.
* @private {!Element}
* @const
*/
this.button_ = button;
this.listen(button, goog.events.EventType.CLICK, this.onButtonClick_);
/**
* Label that displays currently selected item.
* @private {!Element}
* @const
*/
this.label_ =
goog.dom.getRequiredElementByClass(goog.getCssName('label'), button);
/**
* List of selectable items.
* @private {!Element}
* @const
*/
this.menu_ =
goog.dom.getRequiredElementByClass(goog.getCssName('kd-menulist'),
button);
goog.array.forEach(
goog.dom.getElementsByClass(goog.getCssName('kd-menulistitem'), button),
function(item) {
this.listen(item, goog.events.EventType.CLICK, this.onItemClick_);
},
this);
};
goog.inherits(registry.MenuButton, goog.events.EventHandler);
/**
* Returns selected value in menu.
* @return {string}
*/
registry.MenuButton.prototype.getValue = function() {
return goog.dom.getTextContent(
goog.dom.getRequiredElementByClass(
goog.getCssName('selected'),
this.button_));
};
/**
* Main menu button handler.
* @param {!goog.events.BrowserEvent} e
* @private
*/
registry.MenuButton.prototype.onButtonClick_ = function(e) {
if (goog.dom.classlist.contains(this.button_, goog.getCssName('selected'))) {
return;
}
e.stopPropagation();
goog.dom.classlist.add(this.button_, goog.getCssName('selected'));
goog.dom.classlist.add(this.menu_, goog.getCssName('shown'));
this.listenOnce(goog.dom.getDocument().body, goog.events.EventType.CLICK,
this.hideMenu_);
};
/**
* Menu item selection handler.
* @param {!goog.events.BrowserEvent} e
* @private
*/
registry.MenuButton.prototype.onItemClick_ = function(e) {
e.stopPropagation();
if (goog.dom.classlist.contains(this.button_, goog.getCssName('disabled'))) {
return;
}
goog.array.forEach(
goog.dom.getElementsByClass(goog.getCssName('kd-menulistitem'),
this.button_),
function(item) {
goog.dom.classlist.remove(item, goog.getCssName('selected'));
},
this);
goog.asserts.assert(e.target instanceof Element);
goog.dom.classlist.add(e.target, goog.getCssName('selected'));
var text = goog.dom.getTextContent(e.target);
goog.dom.setTextContent(this.label_, text);
goog.events.fireListeners(this.button_, goog.events.EventType.CHANGE,
false, {newValue: text});
this.hideMenu_();
};
/**
* Hide the menu.
* @private
*/
registry.MenuButton.prototype.hideMenu_ = function() {
goog.dom.classlist.remove(this.menu_, goog.getCssName('shown'));
goog.dom.classlist.remove(this.button_, goog.getCssName('selected'));
};

View File

@@ -1,144 +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.AdminSettings');
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.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.admin');
/**
* Admin Settings page, such as allowed TLDs for this registrar.
* @param {!registry.registrar.Console} console
* @param {!registry.Resource} resource the RESTful resource for the registrar.
* @constructor
* @extends {registry.ResourceComponent}
* @final
*/
registry.registrar.AdminSettings = function(console, resource) {
registry.registrar.AdminSettings.base(
this, 'constructor', console, resource,
registry.soy.registrar.admin.settings, console.params.isAdmin, null);
};
goog.inherits(registry.registrar.AdminSettings, registry.ResourceComponent);
/** @override */
registry.registrar.AdminSettings.prototype.bindToDom = function(id) {
registry.registrar.AdminSettings.base(this, 'bindToDom', 'fake');
goog.dom.removeNode(goog.dom.getRequiredElement('reg-app-btn-back'));
};
/** @override */
registry.registrar.AdminSettings.prototype.runAfterRender = function(objArgs) {
const oteButton = goog.dom.getElement('btn-ote-status');
if (oteButton) {
goog.events.listen(
oteButton,
goog.events.EventType.CLICK,
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);
};
/**
* 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.Resource.PARSER_BREAKER_));
var oteResultParent = goog.dom.getRequiredElement('ote-status-area-parent');
if (response.status === 'SUCCESS') {
var results = response.results[0];
goog.soy.renderElement(
oteResultParent, registry.soy.registrar.admin.oteResultsTable,
{completed: results.completed, detailsList: results.details});
} else {
goog.soy.renderElement(
oteResultParent, registry.soy.registrar.admin.oteErrorArea,
{message: response.message});
}
}, 'POST', goog.json.serialize({'clientId': clientId}), {
'X-CSRF-Token': xsrfToken,
'Content-Type': 'application/json; charset=UTF-8'
});
};
/**
* Click handler for TLD add button.
* @private
*/
registry.registrar.AdminSettings.prototype.onTldAdd_ = function() {
const tldInputElt = goog.dom.getRequiredElement('newTld');
const tldElt = goog.soy.renderAsFragment(registry.soy.registrar.admin.tld, {
name: 'allowedTlds[' + this.typeCounts['reg-tlds'] + ']',
tld: tldInputElt.value,
});
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.bind(this.onTldRemove_, this, remBtn));
this.typeCounts['reg-tlds']++;
tldInputElt.value = '';
};
/**
* Click handler for TLD remove button.
* @param {!Element} remBtn The remove button.
* @private
*/
registry.registrar.AdminSettings.prototype.onTldRemove_ = function(remBtn) {
goog.dom.removeNode(goog.dom.getParentElement(remBtn));
};

View File

@@ -1,175 +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.Console');
goog.require('goog.Uri');
goog.require('goog.dispose');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.net.XhrIo');
goog.require('registry.Console');
goog.require('registry.Resource');
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');
goog.require('registry.util');
goog.forwardDeclare('registry.Component');
/**
* The Registrar Console.
* @param {!Object} params Parameters to be passed into templates. These are
* a combination of configurable parameters (e.g. phone number) and
* user/session/registrar specific parameters. See
* registrar/Console.soy#.main for expected contents.
* @constructor
* @extends {registry.Console}
* @final
*/
registry.registrar.Console = function(params) {
registry.registrar.Console.base(this, 'constructor');
/**
* @type {!Object}
*/
this.params = params;
/**
* Component that's currently embedded in the page.
* @type {?registry.Component}
* @private
*/
this.component_ = null;
/**
* Last active nav element.
* @type {?Element}
*/
this.lastActiveNavElt;
/**
* A map from the URL fragment to the component to show.
*
* @type {!Object.<string, function(new:registry.Component,
* !registry.registrar.Console,
* !registry.Resource)>}
*/
this.pageMap = {};
// Homepage. Displayed when there's no fragment, or when the fragment doesn't
// correspond to any view
this.pageMap[''] = registry.registrar.Dashboard;
// Updating the Registrar settings
this.pageMap['security-settings'] = registry.registrar.SecuritySettings;
this.pageMap['contact-settings'] = registry.registrar.ContactSettings;
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.
//
// Both the Console.soy and here, the "hiding the admin console for non
// admins" is purely for "aesthetic / design" reasons and have NO security
// implications.
//
// The security implications are only in the backend where we make sure all
// changes are made by users with the correct access (in other words - we
// don't trust the client-side to secure our application anyway)
if (this.params.isAdmin) {
this.pageMap['admin-settings'] = registry.registrar.AdminSettings;
}
};
goog.inherits(registry.registrar.Console, registry.Console);
/**
* Changes the content area depending on hash path.
*
* <p>Hash path is expected to be of the form:
*
* <pre>
* #type/id
* </pre>
*
* <p>The `id` part may be appended by `()` to specify that the target
* should be a resource create page.
*
* @override
*/
registry.registrar.Console.prototype.handleHashChange = function() {
var hashToken = this.history.getToken();
var parts = hashToken.split('/');
var type = '';
var id = '';
if (parts.length >= 1) {
type = parts[0];
}
if (parts.length == 2) {
id = parts[1];
}
goog.net.XhrIo.cleanup();
var componentCtor = this.pageMap[type];
if (componentCtor == undefined) {
componentCtor = this.pageMap[''];
}
var oldComponent = this.component_;
const resource = new registry.Resource(
new goog.Uri('/registrar-settings'), this.params.clientId,
this.params.xsrfToken);
this.component_ = new componentCtor(this, resource);
this.registerDisposable(this.component_);
this.component_.basePath = type;
this.component_.bindToDom(id);
this.changeNavStyle();
goog.dispose(oldComponent);
};
/** Change nav style. */
registry.registrar.Console.prototype.changeNavStyle = function() {
var hashToken = this.history.getToken();
// Path except id
var slashNdx = hashToken.lastIndexOf('/');
slashNdx = slashNdx == -1 ? hashToken.length : slashNdx;
var regNavlist = goog.dom.getRequiredElement('reg-navlist');
var path = hashToken.substring(0, slashNdx);
var active = regNavlist.querySelector('a[href="#' + path + '"]');
if (active === null) {
registry.util.log('Unknown path or path form in changeNavStyle.');
return;
}
if (this.lastActiveNavElt) {
goog.dom.classlist.remove(
this.lastActiveNavElt, goog.getCssName('domain-active-nav'));
}
goog.dom.classlist.add(active, goog.getCssName('domain-active-nav'));
this.lastActiveNavElt = active;
};

View File

@@ -1,277 +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.ContactSettings');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.json');
goog.require('goog.soy');
goog.require('registry.Resource');
goog.require('registry.ResourceComponent');
goog.require('registry.soy.registrar.contacts');
goog.require('registry.util');
goog.forwardDeclare('registry.registrar.Console');
/**
* Contact Settings page. Registrar Contacts are not really a proper
* REST resource as they're still passed from the server as a member
* field of Registrar, so this class behaves like an item page,
* updating only that field of the Registrar object and not
* implementing the create action from edit_item.
* @param {!registry.registrar.Console} console
* @param {!registry.Resource} resource the RESTful resource for the registrar.
* @constructor
* @extends {registry.ResourceComponent}
* @final
*/
registry.registrar.ContactSettings = function(console, resource) {
registry.registrar.ContactSettings.base(
this, 'constructor', console, resource,
registry.soy.registrar.contacts.contact, console.params.isOwner, null);
};
goog.inherits(registry.registrar.ContactSettings, registry.ResourceComponent);
/** @override */
registry.registrar.ContactSettings.prototype.setupAppbar = function() {
registry.registrar.ContactSettings.base(this, 'setupAppbar');
// Setup delete only on existing items, not on creates.
if (this.model != null) {
var deleteBtn = goog.dom.createDom(
goog.dom.TagName.BUTTON, {
type: 'button',
id: 'reg-app-btn-delete',
className: goog.getCssName('kd-button')
},
'Delete');
goog.events.listen(deleteBtn, goog.events.EventType.CLICK,
goog.bind(this.sendDelete, this));
goog.dom.insertSiblingBefore(deleteBtn,
goog.dom.getRequiredElement('reg-app-btn-cancel'));
}
};
/** @override */
registry.registrar.ContactSettings.prototype.renderItem = function(rspObj) {
var contentElt = goog.dom.getRequiredElement('reg-content');
/** @type {!registry.json.RegistrarContact} */
var contacts = rspObj.contacts;
if (this.id) {
var targetContactNdx;
var targetContact;
for (var c in contacts) {
var ct = contacts[c];
if (ct.emailAddress == this.id) {
targetContactNdx = c;
targetContact = ct;
break;
}
}
if (!targetContact) {
registry.util.butter('No contact with the given email.');
return;
}
var typesList = targetContact.types.toLowerCase().split(',');
var actualTypesLookup = {};
for (var t in typesList) {
actualTypesLookup[typesList[t]] = true;
}
goog.soy.renderElement(
contentElt,
registry.soy.registrar.contacts.contact,
{
item: targetContact,
namePrefix: 'contacts[' + targetContactNdx + '].',
actualTypesLookup: actualTypesLookup,
readonly: (rspObj.readonly || false),
registryLockAllowedForRegistrar: rspObj.registryLockAllowed
});
this.setupAppbar();
this.setupPasswordElemIfNecessary_(targetContactNdx);
} else {
var contactsByType = {};
for (var c in contacts) {
var contact = contacts[c];
var types = contact.types;
if (!types) {
// If the contact has no types, synthesize an "OTHER" type so that it
// still will be displayed in the console.
types = 'OTHER';
}
types = types.split(',');
for (var t in types) {
var type = types[t].toLowerCase();
var contactsList = contactsByType[type];
if (!contactsList) {
contactsByType[type] = contactsList = [];
}
contactsList.push(contact);
}
}
goog.soy.renderElement(
contentElt,
registry.soy.registrar.contacts.set,
{contactsByType: contactsByType });
}
};
/** @override */
registry.registrar.ContactSettings.prototype.add = function() {
var newContactNdx = this.model.contacts.length;
goog.soy.renderElement(goog.dom.getRequiredElement('reg-content'),
registry.soy.registrar.contacts.contact,
{
item: {},
namePrefix: 'contacts[' + newContactNdx + '].',
actualTypesLookup: {},
readonly: false
});
this.toggleEdit();
};
/** @override */
registry.registrar.ContactSettings.prototype.sendDelete = function() {
var ndxToDel = null;
for (var i = 0; i < this.model.contacts.length; i++) {
var contact = this.model.contacts[i];
if (contact.emailAddress == this.id) {
ndxToDel = i;
}
}
if (ndxToDel === null) {
throw new Error('Email to delete does not match model.');
}
var modelCopy = /** @type {!Object}
*/ (JSON.parse(goog.json.serialize(this.model)));
goog.array.removeAt(modelCopy.contacts, ndxToDel);
this.resource.update(modelCopy, goog.bind(this.handleDeleteResponse, this));
};
/** @override */
registry.registrar.ContactSettings.prototype.prepareUpdate =
function(modelCopy) {
var form = registry.util.parseForm('item');
var contact;
// Handle update/create.
if (this.id) {
// Update contact, so overwrite it in the model before sending
// back to server.
var once = false;
for (var c in form.contacts) {
if (once) {
throw new Error('More than one contact parsed from form: ' + c);
}
contact = form.contacts[c];
modelCopy.contacts[c] = contact;
once = true;
}
} else {
// Add contact.
contact = form.contacts.pop();
modelCopy.contacts.push(contact);
}
contact.visibleInWhoisAsAdmin = contact.visibleInWhoisAsAdmin == 'true';
contact.visibleInWhoisAsTech = contact.visibleInWhoisAsTech == 'true';
contact.visibleInDomainWhoisAsAbuse =
contact.visibleInDomainWhoisAsAbuse == 'true';
contact.types = '';
for (var tNdx in contact.type) {
if (contact.type[tNdx]) {
if (contact.types.length > 0) {
contact.types += ',';
}
contact.types += ('' + tNdx).toUpperCase();
}
}
delete contact['type'];
// Override previous domain WHOIS abuse contact.
if (contact.visibleInDomainWhoisAsAbuse) {
for (var c in modelCopy.contacts) {
if (modelCopy.contacts[c].emailAddress != contact.emailAddress) {
modelCopy.contacts[c].visibleInDomainWhoisAsAbuse = false;
}
}
}
this.nextId = contact.emailAddress;
};
// XXX: Should be hoisted up.
/**
* 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 JSON response from the server.
* @override
*/
registry.registrar.ContactSettings.prototype.handleCreateResponse =
function(rsp) {
this.handleUpdateResponse(rsp);
if (rsp.status == 'SUCCESS') {
this.console.view('contact-settings/' + this.nextId);
}
return rsp;
};
/**
* 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 JSON response from the server.
* @override
*/
registry.registrar.ContactSettings.prototype.handleDeleteResponse =
function(rsp) {
this.handleUpdateResponse(rsp);
if (rsp.status == 'SUCCESS') {
this.id = null;
this.console.view('contact-settings');
}
return rsp;
};
// Show or hide the password based on what the user chooses
registry.registrar.ContactSettings.prototype.setupPasswordElemIfNecessary_ =
function(contactIndex) {
var showOrHidePasswordButton = goog.dom.getElement('showOrHideRegistryLockPassword')
var showOrHidePassword = function() {
var inputElement = goog.dom.getRequiredElement(
'contacts[' + contactIndex + '].registryLockPassword')
var type = inputElement.getAttribute('type')
if (type === 'password') {
showOrHidePasswordButton.text = 'Hide password';
inputElement.setAttribute('type', 'text');
} else {
showOrHidePasswordButton.text = 'Show password';
inputElement.setAttribute('type', 'password');
}
};
if (showOrHidePasswordButton != null) {
goog.events.listen(showOrHidePasswordButton,
goog.events.EventType.CLICK, showOrHidePassword, false, this);
}
};

View File

@@ -1,46 +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.ContactUs');
goog.require('goog.dom');
goog.require('registry.Resource');
goog.require('registry.ResourceComponent');
goog.require('registry.soy.registrar.console');
goog.forwardDeclare('registry.registrar.Console');
/**
* Contact Us page.
* @param {!registry.registrar.Console} console
* @param {!registry.Resource} resource the RESTful resource for the registrar.
* @constructor
* @extends {registry.ResourceComponent}
* @final
*/
registry.registrar.ContactUs = function(console, resource) {
registry.registrar.ContactUs.base(
this, 'constructor', console, resource,
registry.soy.registrar.console.contactUs, console.params.isOwner, null);
};
goog.inherits(registry.registrar.ContactUs, registry.ResourceComponent);
/** @override */
registry.registrar.ContactUs.prototype.bindToDom = function(id) {
registry.registrar.ContactUs.base(this, 'bindToDom', '');
goog.dom.removeChildren(goog.dom.getRequiredElement('reg-app-buttons'));
};

View File

@@ -1,89 +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.Dashboard');
goog.require('goog.Timer');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.soy');
goog.require('goog.style');
goog.require('registry.Component');
goog.require('registry.soy.registrar.console');
goog.forwardDeclare('registry.registrar.Console');
/**
* Dashboard for Registrar Console.
* @param {!registry.registrar.Console} console
* @constructor
* @extends {registry.Component}
* @final
*/
registry.registrar.Dashboard = function(console) {
registry.registrar.Dashboard.base(this, 'constructor', console);
/** @private {number} */
this.x_ = 0;
/** @private {?Element} */
this.gear_ = null;
/** @private {?goog.Timer} */
this.timer_ = null;
};
goog.inherits(registry.registrar.Dashboard, registry.Component);
/** @override */
registry.registrar.Dashboard.prototype.bindToDom = function(id) {
registry.registrar.Dashboard.base(this, 'bindToDom', '');
goog.dom.removeChildren(goog.dom.getRequiredElement('reg-app-buttons'));
goog.soy.renderElement(goog.dom.getElement('reg-content'),
registry.soy.registrar.console.dashboard,
this.console.params);
goog.events.listen(goog.dom.getElement('rotate'),
goog.events.EventType.CLICK,
goog.bind(this.rotate_, this));
this.gear_ = goog.dom.getRequiredElement('gear');
};
/**
* Let's do the twist.
* @private
*/
registry.registrar.Dashboard.prototype.rotate_ = function() {
this.timer_ = new goog.Timer(10);
this.registerDisposable(this.timer_);
goog.events.listen(this.timer_, goog.Timer.TICK,
goog.bind(this.rotateCall_, this));
this.timer_.start();
};
/**
* No really this time!
* @private
*/
registry.registrar.Dashboard.prototype.rotateCall_ = function() {
this.x_++;
goog.style.setStyle(this.gear_, 'transform', 'rotate(' + this.x_ + 'deg)');
if (this.x_ == 360) {
this.timer_.stop();
}
};

View File

@@ -1,61 +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.
/**
* @fileoverview Entry point for the registrar console.
*/
goog.provide('registry.registrar.main');
goog.require('registry.registrar.Console');
/**
* Instantiates a registry object, which syncs with the server.
* Sub-templates are invoked based on location/pathname, to choose
* either Registry or Registrar pages.
*
* @param {string} xsrfToken populated by server-side soy template.
* @param {string} clientId The registrar clientId.
* @param {boolean} isAdmin
* @param {boolean} isOwner
* @param {string} productName the product name displayed by the UI.
* @param {string} integrationEmail
* @param {string} supportEmail
* @param {string} announcementsEmail
* @param {string} supportPhoneNumber
* @param {string} technicalDocsUrl
* @param {string} environment
* @export
*/
registry.registrar.main = function(
xsrfToken, clientId, isAdmin, isOwner, productName, integrationEmail,
supportEmail, announcementsEmail, supportPhoneNumber, technicalDocsUrl,
environment) {
const console = new registry.registrar.Console({
xsrfToken: xsrfToken,
clientId: clientId,
isAdmin: isAdmin,
isOwner: isOwner,
productName: productName,
integrationEmail: integrationEmail,
supportEmail: supportEmail,
announcementsEmail: announcementsEmail,
supportPhoneNumber: supportPhoneNumber,
technicalDocsUrl: technicalDocsUrl,
environment: environment,
});
console.setUp();
};

View File

@@ -1,228 +0,0 @@
// 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.isAdmin = objArgs.isAdmin;
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) {
this.registryLockEmailAddress = locksDetails.email;
// Listen to the lock-domain 'submit' button click
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,
isAdmin: this.isAdmin,
emailAddress: this.registryLockEmailAddress});
parentElement.prepend(modalElement);
if (domain == null) {
goog.dom.getRequiredElement('domain-lock-input-value').focus();
} else {
var passwordElem = goog.dom.getElement('domain-lock-password');
if (passwordElem != null) {
passwordElem.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);
// Listen to the "submit" click and also the user hitting enter
goog.events.listen(
goog.dom.getRequiredElement('domain-lock-submit'),
goog.events.EventType.CLICK,
e => this.lockOrUnlockDomain_(isLock, e),
false,
this);
[goog.dom.getElement('domain-lock-password'),
goog.dom.getElement('domain-lock-input-value')].forEach(elem => {
if (elem != null) {
goog.events.listen(
elem,
goog.events.EventType.KEYPRESS,
e => {
if (e.keyCode === goog.events.KeyCodes.ENTER) {
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 passwordElem = goog.dom.getElement('domain-lock-password');
var password = passwordElem == null ? null : passwordElem.value;
var relockDuration = this.getRelockDurationFromModal_()
goog.net.XhrIo.send('/registry-lock-post',
e => this.fillLocksPage_(e),
'POST',
goog.json.serialize({
'registrarId': this.clientId,
'domainName': domain,
'isLock': isLock,
'password': password,
'relockDurationMillis': relockDuration
}), {
'X-CSRF-Token': this.xsrfToken,
'Content-Type': 'application/json; charset=UTF-8'
});
}
/**
* Returns the duration after which we will re-lock a locked domain. Will return null if we
* are locking a domain, or if the user selects the "Never" option
* @private
*/
registry.registrar.RegistryLock.prototype.getRelockDurationFromModal_ = function() {
var inputElements = goog.dom.getElementsByTagNameAndClass("input", "relock-duration-input");
for (var i = 0; i < inputElements.length; i++) {
var elem = inputElements[i];
if (elem.checked && elem.value !== "0") {
return elem.value;
}
}
return null;
}
/**
* 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);
};

View File

@@ -1,47 +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.Resources');
goog.require('goog.dom');
goog.require('registry.Resource');
goog.require('registry.ResourceComponent');
goog.require('registry.soy.registrar.console');
goog.forwardDeclare('registry.registrar.Console');
/**
* Resources and billing page.
* @param {!registry.registrar.Console} console
* @param {!registry.Resource} resource the RESTful resource for the registrar.
* @constructor
* @extends {registry.ResourceComponent}
* @final
*/
registry.registrar.Resources = function(console, resource) {
registry.registrar.Resources.base(
this, 'constructor', console, resource,
registry.soy.registrar.console.resources, console.params.isOwner, null);
};
goog.inherits(registry.registrar.Resources,
registry.ResourceComponent);
/** @override */
registry.registrar.Resources.prototype.bindToDom = function(id) {
registry.registrar.Resources.base(this, 'bindToDom', 'fake');
goog.dom.removeNode(goog.dom.getRequiredElement('reg-app-btn-back'));
};

View File

@@ -1,106 +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.SecuritySettings');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.soy');
goog.require('registry.Resource');
goog.require('registry.ResourceComponent');
goog.require('registry.soy.registrar.security');
goog.forwardDeclare('registry.registrar.Console');
/**
* Security Settings page.
* @param {!registry.registrar.Console} console
* @param {!registry.Resource} resource the RESTful resource for the registrar.
* @constructor
* @extends {registry.ResourceComponent}
* @final
*/
registry.registrar.SecuritySettings = function(console, resource) {
registry.registrar.SecuritySettings.base(
this, 'constructor', console, resource,
registry.soy.registrar.security.settings, console.params.isOwner, null);
};
goog.inherits(registry.registrar.SecuritySettings, registry.ResourceComponent);
/** @override */
registry.registrar.SecuritySettings.prototype.bindToDom = function(id) {
registry.registrar.SecuritySettings.base(this, 'bindToDom', 'fake');
goog.dom.removeNode(goog.dom.getRequiredElement('reg-app-btn-back'));
};
/** @override */
registry.registrar.SecuritySettings.prototype.setupEditor =
function(objArgs) {
goog.dom.classlist.add(goog.dom.getRequiredElement('ips'),
goog.getCssName('editing'));
var ips = goog.dom.getElementsByClass(goog.getCssName('ip'),
goog.dom.getRequiredElement('ips'));
goog.array.forEach(ips, function(ip) {
var remBtn = goog.dom.getChildren(ip)[0];
goog.events.listen(remBtn,
goog.events.EventType.CLICK,
goog.bind(this.onIpRemove_, this, remBtn));
}, this);
this.typeCounts['reg-ips'] = objArgs.ipAddressAllowList ?
objArgs.ipAddressAllowList.length : 0;
goog.events.listen(goog.dom.getRequiredElement('btn-add-ip'),
goog.events.EventType.CLICK,
this.onIpAdd_,
false,
this);
};
/**
* Click handler for IP add button.
* @private
*/
registry.registrar.SecuritySettings.prototype.onIpAdd_ = function() {
var ipInputElt = goog.dom.getRequiredElement('newIp');
var ipElt = goog.soy.renderAsFragment(registry.soy.registrar.security.ip, {
name: 'ipAddressAllowList[' + this.typeCounts['reg-ips'] + ']',
ip: ipInputElt.value
});
goog.dom.appendChild(goog.dom.getRequiredElement('ips'), ipElt);
var remBtn = goog.dom.getFirstElementChild(ipElt);
goog.dom.classlist.remove(remBtn, goog.getCssName('hidden'));
goog.events.listen(remBtn, goog.events.EventType.CLICK,
goog.bind(this.onIpRemove_, this, remBtn));
this.typeCounts['reg-ips']++;
ipInputElt.value = '';
};
/**
* Click handler for IP remove button.
* @param {!Element} remBtn The remove button.
* @private
*/
registry.registrar.SecuritySettings.prototype.onIpRemove_ =
function(remBtn) {
goog.dom.removeNode(goog.dom.getParentElement(remBtn));
};

View File

@@ -1,46 +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.WhoisSettings');
goog.require('goog.dom');
goog.require('registry.Resource');
goog.require('registry.ResourceComponent');
goog.require('registry.soy.registrar.whois');
goog.forwardDeclare('registry.registrar.Console');
/**
* WHOIS Settings page.
* @param {!registry.registrar.Console} console
* @param {!registry.Resource} resource the RESTful resource for the registrar.
* @constructor
* @extends {registry.ResourceComponent}
* @final
*/
registry.registrar.WhoisSettings = function(console, resource) {
registry.registrar.WhoisSettings.base(
this, 'constructor', console, resource,
registry.soy.registrar.whois.settings, console.params.isOwner, null);
};
goog.inherits(registry.registrar.WhoisSettings, registry.ResourceComponent);
/** @override */
registry.registrar.WhoisSettings.prototype.bindToDom = function(id) {
registry.registrar.WhoisSettings.base(this, 'bindToDom', 'fake');
goog.dom.removeNode(goog.dom.getRequiredElement('reg-app-btn-back'));
};

View File

@@ -1,86 +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.Resource');
goog.require('goog.json');
goog.require('registry.Session');
goog.forwardDeclare('goog.Uri');
/**
* Provide a CRUD view of a server resource.
*
* @param {!goog.Uri} baseUri Target RESTful resource.
* @param {string} id the ID of the target resource
* @param {string} xsrfToken Security token to pass back to the server.
* @extends {registry.Session}
* @constructor
*/
registry.Resource = function(baseUri, id, xsrfToken) {
registry.Resource.base(this, 'constructor', baseUri, xsrfToken);
/** @const @private {string} the ID of the target resource. */
this.id_ = id;
};
goog.inherits(registry.Resource, registry.Session);
/**
* Get the resource from the server.
*
* @param {!Object} args Params for server.
* @param {!Function} callback for retrieved resource.
*/
registry.Resource.prototype.read = function(args, callback) {
this.send_('read', args, callback);
};
/**
* Update the resource on the server.
*
* @param {!Object} args params for server.
* @param {!Function} callback on success.
* @throws {!Exception} if the 'op' field is set on args.
*/
registry.Resource.prototype.update = function(args, callback) {
this.send_('update', args, callback);
};
/**
* RESTful access to resources on the server.
*
* @param {string} opCode One of (create|read|update)
* @param {!Object} argsObj arguments for the operation.
* @param {!Function} callback For XhrIo result throws.
* @private
*/
registry.Resource.prototype.send_ =
function(opCode, argsObj, callback) {
// NB: must be declared this way in order to avoid compiler renaming
var req = {};
req['op'] = opCode;
req['args'] = argsObj;
req['id'] = this.id_;
this.sendXhrIo(goog.json.serialize(req), callback);
};
/**
* JSON response prefix which prevents evaluation.
* @const
*/
registry.Resource.PARSER_BREAKER_ = ')]}\'\n';

View File

@@ -1,191 +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.ResourceComponent');
goog.require('goog.dom');
goog.require('goog.json');
goog.require('goog.object');
goog.require('registry.EditItem');
goog.require('registry.forms');
goog.require('registry.util');
goog.forwardDeclare('registry.Console');
goog.forwardDeclare('registry.Resource');
/**
* The ResourceComponent class respresents server state for a named
* resource and binds UI CRUD operations on it, or its constituent
* collection.
* @param {!registry.Console} console console singleton.
* @param {!registry.Resource} resource the RESTful resource.
* @param {!Function} itemTmpl
* @param {boolean} isEditable if true, the "edit" button will be enabled
* @param {Function} renderSetCb may be null if this resource is only
* ever an item.
* @constructor
* @extends {registry.EditItem}
*/
registry.ResourceComponent = function(
console,
resource,
itemTmpl,
isEditable,
renderSetCb) {
registry.ResourceComponent.base(
this, 'constructor', console, itemTmpl, isEditable);
/** @type {!registry.Resource} */
this.resource = resource;
/** @type {Function} */
this.renderSetCb = renderSetCb;
};
goog.inherits(registry.ResourceComponent, registry.EditItem);
/** @override */
registry.ResourceComponent.prototype.renderItem = function(rspObj) {
// Augment the console parameters with the response object, we'll need both.
var params = goog.object.clone(this.console.params);
goog.object.extend(params, rspObj);
registry.ResourceComponent.base(this, 'renderItem', params);
};
/** @override */
registry.ResourceComponent.prototype.bindToDom = function(id) {
registry.ResourceComponent.base(this, 'bindToDom', id);
this.fetchItem(id);
};
/** @override */
registry.ResourceComponent.prototype.back = function() {
this.console.view(this.basePath);
};
/** @override */
registry.ResourceComponent.prototype.fetchItem = function(id) {
this.resource.read({}, goog.bind(this.handleFetchItem, this, id));
};
/** @override */
registry.ResourceComponent.prototype.handleFetchItem = function(id, rsp) {
// XXX: Two different protocols are supported here. The new style used in the
// registrar console is first, followed by the item/set style used by
// the admin console.
if ('status' in rsp) {
// New style.
if (rsp.status == 'SUCCESS') {
this.model = rsp.results[0];
this.model.readonly = true;
this.processItem();
this.renderItem(this.model);
} else {
// XXX: Happens if the server restarts while the client has an
// open-session. This should retry.
registry.forms.resetErrors();
registry.forms.displayError(rsp['message'], rsp['field']);
}
} else if ('item' in rsp) {
this.model = rsp.item;
this.model.readonly = true;
this.processItem();
this.renderItem(this.model);
} else if ('set' in rsp && this.renderSetCb != null) {
// XXX: This conditional logic should be hoisted to edit_item when
// collection support is improved.
goog.dom.removeChildren(goog.dom.getRequiredElement('reg-app-buttons'));
this.renderSetCb(goog.dom.getRequiredElement('reg-content'), rsp);
} else {
registry.util.log('unknown message type in handleFetchItem');
}
};
/** @override */
registry.ResourceComponent.prototype.sendUpdate = function() {
var modelCopy = /** @type {!Object}
*/ (JSON.parse(goog.json.serialize(this.model)));
this.prepareUpdate(modelCopy);
if (this.id) {
this.resource.update(modelCopy, goog.bind(this.handleUpdateResponse, this));
} else {
this.resource.update(modelCopy, goog.bind(this.handleCreateResponse, this));
}
};
/** @override */
registry.ResourceComponent.prototype.prepareUpdate = function(modelCopy) {
var form = registry.util.parseForm('item');
for (var ndx in form) {
modelCopy[ndx] = form[ndx];
}
};
/** @override */
registry.ResourceComponent.prototype.handleUpdateResponse = function(rsp) {
if (rsp.status) {
if (rsp.status != 'SUCCESS') {
registry.forms.resetErrors();
registry.forms.displayError(rsp['message'], rsp['field']);
return rsp;
}
// XXX: Vestigial state from admin console. Shouldn't be possible to be
// null.
if (this.id) {
this.fetchItem(this.id || '');
this.toggleEdit();
}
return rsp;
}
// XXX: Should be removed when admin console uses new response format.
if (rsp instanceof Object && 'results' in rsp) {
registry.util.butter(rsp['results']);
this.bindToDom(this.nextId || '');
this.nextId = null;
} else {
registry.util.butter(rsp.toString());
}
return rsp;
};
/**
* Handle resource create response.
* @param {!Object} rsp Decoded JSON response from the server.
* @return {!Object} a result object describing next steps. On
* success, if next is defined, visit(ret.next) is called, otherwise
* if err is set, the butterbar message is set to it.
*/
registry.ResourceComponent.prototype.handleCreateResponse =
goog.abstractMethod;
/**
* Handle resource delete response.
* @param {!Object} rsp Decoded JSON response from the server.
* @return {!Object} a result object describing next steps. On
* success, if next is defined, visit(ret.next) is called, otherwise
* if err is set, the butterbar message is set to it.
*/
registry.ResourceComponent.prototype.handleDeleteResponse =
goog.abstractMethod;

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.Session');
goog.require('goog.json');
goog.require('goog.net.XhrIo');
goog.require('registry.util');
goog.forwardDeclare('goog.Uri');
/**
* XHR launcher for JSON requests.
* @param {!goog.Uri} defaultUri URI to which requests are POSTed.
* @param {string} xsrfToken Cross-site request forgery protection token.
* @constructor
* @template REQUEST, RESPONSE
*/
registry.Session = function(defaultUri, xsrfToken) {
/**
* URI to which requests are posted.
* @protected {!goog.Uri}
* @const
*/
this.uri = defaultUri;
/**
* XHR request headers.
* @private {!Object<string, string>}
* @const
*/
this.headers_ = {
'Content-Type': 'application/json; charset=utf-8',
'X-CSRF-Token': xsrfToken,
'X-Requested-With': 'XMLHttpRequest'
};
};
/**
* Abstract method to send a request to the server.
* @param {REQUEST} body HTTP request body as a string or JSON object.
* @param {function(RESPONSE)} onSuccess XHR success callback.
* @param {function(string)=} opt_onError XHR error callback. The default action
* is to show a bloody butterbar.
* @final
*/
registry.Session.prototype.sendXhrIo =
function(body, onSuccess, opt_onError) {
goog.net.XhrIo.send(
this.uri.toString(),
goog.bind(this.onXhrComplete_, this, onSuccess,
opt_onError || goog.bind(this.displayError_, this)),
'POST',
goog.isObject(body) ? goog.json.serialize(body) : body,
this.headers_);
};
/**
* Handler invoked when an asynchronous request is complete.
* @param {function(RESPONSE)} onSuccess Success callback.
* @param {function(string)} onError Success callback.
* @param {{target: !goog.net.XhrIo}} e XHR event.
* @private
*/
registry.Session.prototype.onXhrComplete_ = function(onSuccess, onError, e) {
if (e.target.isSuccess()) {
onSuccess(/** @type {!RESPONSE} */ (
e.target.getResponseJson(registry.Session.PARSER_BREAKER_)));
} else {
onError(e.target.getLastError());
}
};
/**
* JSON response prefix which prevents evaluation.
* @private {string}
* @const
*/
registry.Session.PARSER_BREAKER_ = ')]}\'\n';
/**
* Displays `message` to user in bloody butterbar.
* @param {string} message
* @private
*/
registry.Session.prototype.displayError_ = function(message) {
registry.util.butter(
this.uri.toString() + ': ' + message + '. Please reload.', true);
};

View File

@@ -1,215 +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.util');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.soy');
/**
* Logging function that delegates to `console.log()`.
* @param {...*} var_args
*/
registry.util.log = function(var_args) {
if (goog.DEBUG) {
if (goog.global.console !== undefined && goog.global.console['log'] !== undefined) {
goog.global.console.log.apply(goog.global.console, arguments);
}
}
};
/**
* CSS class for hiding an element whose visibility can be toggled.
* @type {string}
* @const
*/
registry.util.cssHidden = goog.getCssName('hidden');
/**
* CSS class for showing an element whose visibility can be toggled.
* @type {string}
* @const
*/
registry.util.cssShown = goog.getCssName('shown');
/**
* Changes element visibility by toggling CSS `shown` to `hidden`.
* @param {!Element|string} element Element or id attribute of element.
* @param {boolean} visible Shows `element` if true, or else hides it.
*/
registry.util.setVisible = function(element, visible) {
goog.dom.classlist.addRemove(
goog.dom.getElement(element),
visible ? registry.util.cssHidden : registry.util.cssShown,
visible ? registry.util.cssShown : registry.util.cssHidden);
};
/**
* Show a buttebar with the given message. A dismiss link will be added.
* @param {string} message the message to show the user.
* @param {boolean=} opt_isFatal indicates butterbar should be blood red. This
* should only be used when an RPC returns a non-200 status.
*/
registry.util.butter = function(message, opt_isFatal) {
goog.dom.setTextContent(
goog.dom.getElementByClass(goog.getCssName('kd-butterbar-text')),
message);
var butterbar =
goog.dom.getRequiredElementByClass(goog.getCssName('kd-butterbar'));
registry.util.setVisible(butterbar, true);
if (opt_isFatal) {
goog.dom.classlist.add(butterbar, goog.getCssName('fatal'));
} else {
goog.dom.classlist.remove(butterbar, goog.getCssName('fatal'));
}
};
/**
* Hides the butterbar.
*/
registry.util.unbutter = function() {
registry.util.setVisible(
goog.dom.getRequiredElementByClass(goog.getCssName('kd-butterbar')),
false);
};
/**
* Renders the tmpl at and then moves it before the given elt.
* @param {Element|string} id dom id of the refElt to render before.
* @param {function()} tmpl template to render.
* @param {!Object} tmplParams params to pass to the template.
* @return {!Element} the rendered row.
*/
registry.util.renderBeforeRow = function(id, tmpl, tmplParams) {
var refElt = goog.dom.getElement(id);
goog.soy.renderElement(refElt, tmpl, tmplParams);
var prevSib = goog.dom.getPreviousElementSibling(refElt);
goog.dom.removeNode(refElt);
refElt.removeAttribute('id');
goog.dom.insertSiblingAfter(refElt, prevSib);
var newAnchorRefElt = goog.dom.createDom(refElt.tagName, {'id': id});
goog.dom.insertSiblingAfter(newAnchorRefElt, refElt);
return refElt;
};
/**
* Turns an HTML form's named elements into a JSON data structure with
* Pablo's black magick.
* @param {string} formName the name of the form to be parsed.
* @throws {Error} if `formName` couldn't be found.
* @return {!Object} the parsed form values as an object.
*/
registry.util.parseForm = function(formName) {
var form = /** @type {HTMLFormElement}
*/ (document.querySelector('form[name=' + formName + ']'));
if (form == null) {
throw new Error('No such form named ' + formName);
}
var obj = {};
// Find names first, since e.g. radio buttons have two elts with the
// same name.
var eltNames = {};
for (var i = 0; i < form.elements.length; i++) {
var elt = form.elements[i];
if (elt.name == '') {
continue;
}
eltNames[elt.name] = null;
}
for (var eltName in eltNames) {
var elt = form.elements[eltName];
var val;
if (elt.type == 'checkbox') {
val = elt.checked;
} else {
val = elt.value;
}
registry.util.expandObject_(obj, eltName, val);
}
return obj;
};
/**
* Give the object a value at the given path. Paths are split on dot
* and array elements are recognized.
*
* <ul>
* <li>a = 1
* <li>foo:a = 1.5
* <li>b.c = 2
* <li>b.d = 3
* <li>c[0] = 4
* <li>c[1] = 5
* <li>d[0].a = 6
* <li>d[1].foo:b = 7
* <li>d[1].@b = 8
* </ul>
*
* Yields the following object:
* <pre>
* {
* a: '1',
* 'foo:a': '1.5',
* b: {
* c: '2',
* d: '3'
* },
* c: ['4','5'],
* d: [{a:'6'},{'foo:b':'7'},{'@b':'8'}]
* }
* </pre>
*
* @param {!Object} obj
* @param {string} pathSpec
* @param {string|Array.<string>|null} val
* @private
*/
registry.util.expandObject_ = function(obj, pathSpec, val) {
var path = pathSpec.split('.');
for (var p = 0; p < path.length; p++) {
var fieldName = path[p];
var arrElt = fieldName.match(/^([\w:]+)\[(\d+)\]$/);
if (arrElt) {
var arrName = arrElt[1];
var arrNdx = arrElt[2];
if (!obj[arrName]) {
obj[arrName] = [];
}
obj = obj[arrName];
fieldName = arrNdx;
if (!obj[arrNdx]) {
obj[arrNdx] = {};
}
} else {
if (!obj[fieldName]) {
obj[fieldName] = {};
}
}
if (p == path.length - 1) {
obj[fieldName] = val;
} else {
obj = obj[fieldName];
}
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,144 +0,0 @@
// Copyright 2018 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.
{namespace registry.soy.registrar.admin}
/** Registrar admin settings page for view and edit. */
{template .settings}
{@param allowedTlds: list<string>}
{@param type: string} // the registrar type, e.g. REAL, OTE, TEST, etc.
{@param environment: string} // the server environment e.g. PRODUCTION, SANDBOX
<form name="item" class="{css('item')} {css('registrar')}">
<h1>Administrator settings</h1>
<table>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Allowed TLDs</label>
<span class="{css('description')}">set or remove TLDs this
client is allowed access to.</span>
<td class="{css('setting')}">
<div class="{css('info')} {css('summary')}">
<div id="tlds">
{for $tld in $allowedTlds}
{call .tld}
{param name: 'allowedTlds[' + index($tld) + ']' /}
{param tld: $tld /}
{/call}
{/for}
</div>
<div class="{css('hidden')}">
<input id="newTld" value="" placeholder="Enter TLD"/>
<button id="btn-add-tld" type="button"
class="{css('kd-button')} {css('btn-add')}">Add</button>
</div>
</div>
{if $environment != 'PRODUCTION'}
<tr class="{css('kd-settings-pane-section')}">
<td>
<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>
{/if}
{if $type == 'OTE'}
{call .oteStatus}
{param registrarType: $type /}
{/call}
{/if}
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Create new registrar</label>
<td class="{css('setting')}">
<p><a href="/registrar-create">New registrar form</a>
</p></td>
</tr>
</table>
</form>
{/template}
/** TLD form input. */
{template .tld}
{@param name: string}
{@param tld: string}
<div class="{css('tld')}">
<button type="button" class="{css('kd-button')} {css('btn-remove')} {css('hidden')}">
<i class="{css('icon-remove')} {css('edit')}">x</i>
</button>
<input name="{$name}" value="{$tld}" readonly>
</div>
{/template}
{template .oteStatus}
{@param registrarType: string}
<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')}
{if $registrarType != 'OTE'} {css('disabled')} {/if}">
Check OT&amp;E status
</button>
</td>
<td id="ote-status-area-parent" class="{css('setting')}"></td>
</tr>
{/template}
{template .oteResultsTable}
{@param completed: bool}
{@param detailsList: list<[description: string, timesPerformed: int, requirement: int, completed: bool]>}
<table id="ote-results-table">
{if $completed}
<tr class={css('ote-fulfilled')}>
<td>Status:</td>
<td>Completed</td>
</tr>
{else}
<tr class={css('ote-unfulfilled')}>
<td>Status:</td>
<td>Not Completed</td>
</tr>
{/if}
<tr class="{css('ote-results-header')}">
<th class="{css('ote-results-header-cell')}"><b>Test Name</b></th>
<th class="{css('ote-results-header-cell')}"><b>Actions Performed</b></th>
</tr>
{for $detail in $detailsList}
{if $detail.completed}
<tr class="{css('ote-fulfilled')}">
<td>{$detail.description}</td>
<td>Completed</td>
</tr>
{elseif $detail.timesPerformed > 0}
<tr class="{css('ote-semifulfilled')}">
<td>{$detail.description}</td>
<td>{$detail.timesPerformed} of {$detail.requirement}</td>
</tr>
{else}
<tr class="{css('ote-unfulfilled')}">
<td>{$detail.description}</td>
<td>Not started</td>
</tr>
{/if}
{/for}
</table>
{/template}
{template .oteErrorArea}
{@param message: string}
<p id="ote-status-area">Error: {$message}</p>
{/template}

View File

@@ -1,34 +0,0 @@
// Copyright 2019 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.
{namespace registry.soy.analytics}
/**
* The JS template required to install Google Analytics for the registrar console.
*/
{template .googleAnalytics}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{let $id: $analyticsConfig.googleAnalyticsId /}
{if $id}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={$id}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){lb}dataLayer.push(arguments);{rb}
gtag('js', new Date());
gtag('config', {$id});
</script>
{/if}
{/template}

View File

@@ -1,367 +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.
{namespace registry.soy.registrar.console}
/**
* Main registrar page. We use a single page architecture (SPA) so content is
* filled in dynamically into reg-app element via JS rendering of Component.soy
* and other templates within it.
*/
{template .main}
{@param xsrfToken: string} /** Security token. */
{@param clientId: string} /** Registrar client identifier. */
{@param allClientIds: list<string>} /** All registrar client identifiers for the user. */
{@param isAdmin: bool}
{@param isOwner: bool}
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param productName: string} /** Name to display for this software product. */
{@param integrationEmail: string}
{@param supportEmail: string}
{@param announcementsEmail: string}
{@param supportPhoneNumber: string}
{@param technicalDocsUrl: string}
{@param environment: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{@param includeDeprecationWarning: bool}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Registrar Console' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
{call registry.soy.console.googlebar data="all" /}
<div id="reg-app" lang="en-US">
<div id="reg-appbar" class="{css('kd-appbar')}">
<div id="reg-accessing-as-role" class="{css('kd-description')}">
Accessing <span class="{css('kd-value')}">{$clientId}</span> as{sp}
{if $isOwner}<span class="{css('kd-value')}">Owner</span>{/if}
{if $isAdmin}<span class="{css('kd-value')}">Admin</span>{/if}
{if length($allClientIds) > 1}
{sp}(Switch registrar: {call .clientIdSelect_ data="all" /})
{/if}
</div>
{if $includeDeprecationWarning}
<div id="reg-deprecation-warning">
<h1>Note: this console is deprecated and will be deactivated in October 2024.
Please use the <a href="/console">new console</a> instead.
</h1>
</div>
{/if}
<div id="reg-app-buttons" class="{css('kd-buttonbar')} {css('left')}"></div>
</div>
{call .navbar_ data="all" /}
<div id="reg-content-and-footer">
<div id="reg-content">
// Dynamic content goes here.
</div>
{call registry.soy.console.footer /}
</div>
</div>
{switch DEBUG}
{case google.registry.ui.ConsoleDebug.PRODUCTION}
<script src="/assets/js/registrar_bin.js"></script>
{case google.registry.ui.ConsoleDebug.DEBUG}
<script src="/assets/js/registrar_dbg.js"></script>
{case google.registry.ui.ConsoleDebug.RAW}
<script>var CLOSURE_NO_DEPS = true;</script>
<script src="/assets/sources/com_google_javascript_closure_library/closure/googbase.js"></script>
<script src="/assets/sources/domain_registry/java/google/registry/ui/deps.js"></script>
<script>goog.require('registry.registrar.main');</script>
{/switch}
{if isNonnull(DEBUG)}
<script>
registry.registrar.main({$xsrfToken},
{$clientId},
{if $isAdmin}true{else}false{/if},
{if $isOwner}true{else}false{/if},
{$productName},
{$integrationEmail},
{$supportEmail},
{$announcementsEmail},
{$supportPhoneNumber},
{$technicalDocsUrl},
{$environment});
</script>
{/if}
{/template}
/** Sidebar nav. Ids on each elt for testing only. */
{template .navbar_ visibility="private"}
{@param isAdmin: bool}
<div id="reg-nav" class="{css('kd-content-sidebar')}">
<ul id="reg-navlist">
<li>
<a href="#">Home</a>
<li>
<a href="#resources">Resources &amp; billing</a>
<li>
<ul>
<span class="{css('reg-navlist-sub')}">Settings</span>
<li>
<a href="#whois-settings">WHOIS</a>
<li>
<a href="#security-settings">Security</a>
<li>
<a href="#contact-settings">Contact</a>
<li>
<a href="#registry-lock">Registry lock</a>
{if $isAdmin}
<li>
<a href="#admin-settings">Admin</a>
{/if}
</ul>
<li>
<a href="#contact-us">Contact us</a>
</ul>
</div>
{/template}
/** Drop-down selection for the clientId. */
{template .clientIdSelect_ visibility="private"}
{@param clientId: string} /** Registrar client identifier. */
{@param allClientIds: list<string>}
<form>
<select name="clientId"
id="select-client-id"
class="{css('kd-button')} {css('kd-button-submit')}"
onchange='this.form.submit()'>
<option value="">[auto select]</option>
{for $id in $allClientIds}
<option value="{$id}" {if $id == $clientId}selected{/if}>{$id}</option>
{/for}
</select>
</form>
{/template}
/**
* Feature disabled
*/
{template .disabled}
{@param logoFilename: string}
{@param productName: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Console Disabled' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
<div class="{css('whoAreYou-disabled')}">
<a class="{css('logo')}" href="/registrar">
<img src="/assets/images/{$logoFilename}" alt="{$productName}">
</a>
<h1>Console is disabled</h1>
<p>
The {$productName} registrar console is temporarily disabled. Please
contact your customer service representative for more information.
<p>
<img src="/assets/images/android_sad.png">
</div>
{/template}
/**
* Who goes thar?!
*/
{template .whoareyou}
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param logoFilename: string}
{@param productName: string}
{@param? clientId: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Not Authorized' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
<div class="{css('whoAreYou')}">
<a class="{css('logo')}" href="/registrar">
<img src="/assets/images/{$logoFilename}" alt="{$productName}">
</a>
<h1>You need permission</h1>
{if isNonnull($clientId)} // A clientId was given - but we don't have access to it
<p>
The account you are logged in as is not associated with the registrar
{sp}{$clientId}. Please contact your customer service representative or
switch to an account associated with {$clientId}. Alternatively, click
{sp}<a href="?">here</a> to find a registrar associated with your
account.
{else}
<p>
The account you are logged in as is not associated with {$productName}.
Please contact your customer service representative or
switch to an account associated with {$productName}.
{/if}
<p>
You are signed in as <strong>{$username}</strong>.
<div>
<a href="{$logoutUrl}"
class="{css('kd-button')} {css('kd-button-submit')}"
tabindex="-1">Logout and switch to another account</a>
{if isNonnull($clientId)} // A clientId was given - but we don't have access to it
{sp}
<a href="?"
class="{css('kd-button')} {css('kd-button-submit')}"
tabindex="-1">Find registrar associated with your account</a>
{/if}
</div>
</div>
{/template}
/** Welcome text and nav. */
{template .dashboard}
{@param productName: string}
<div id="domain-registrar-dashboard">
<h1>Welcome to the {$productName} Registrar Console<super>BETA</super></h1>
<p>This console can help you manage your relationship with {$productName} and
allow self-service for key operations.</p>
<table>
<tr>
<td>
<div class="{css('dashbox')}">
<img src="/assets/images/homeResources.png">
<h2>Access Resources</h2>
Use Google Drive to view<br>
onboarding FAQs, technical<br>
documentation &amp; billing reports.
</div>
<td>
<div class="{css('dashbox')}">
<img id="gear" src="/assets/images/homeSettings.png">
<h2>Manage Settings</h2>
Security, WHOIS &amp; contact<br>
settings are easy to view and edit.
</div>
<td>
<div class="{css('dashbox')}">
<img src="/assets/images/homeContact.png">
<h2>Contact Us</h2>
View important phone &amp; email<br>
contact information for<br>
{$productName}.
</div>
</tr>
</table>
<p><img id="rotate" src="/assets/images/explore_24.png">We're
hard at work creating new features for the console. Stay tuned
for updates!
</div>
{/template}
/** Contact us. */
{template .contactUs}
{@param? phonePasscode: string}
{@param integrationEmail: string}
{@param supportEmail: string}
{@param announcementsEmail: string}
{@param supportPhoneNumber: string}
<div id="domain-registrar-contact-us" class="{css('item')}">
<h1>Contact us</h1>
<p>Our support team can assist you with any technical or operational
questions you may have regarding our registry services.
<table>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Email</label>
</td>
<td class="{css('setting')}">
<p>
<a href="mailto:{$integrationEmail}">{$integrationEmail}</a><br>
For help with OT&amp;E sandbox and certification, or new
technical requirements for any of our new TLD launches.
<p>
<a href="mailto:{$supportEmail}">{$supportEmail}</a><br>
For general purpose questions once you are integrated
with our registry system. If the issue is urgent, please put
&quot;Urgent&quot; in the email title.
<p class="{css('description')}">Note: You may receive occasional service
announcements
via <strong>{$announcementsEmail}</strong>. You
will not be able to reply to those messages.
<tr><td colspan="2"><hr>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Phone</label>
<span class="{css('description')}">For general support inquiries 24x7</span>
</td>
<td class="{css('setting')}">
<p>Please be ready with your account name and telephone passcode
when contacting us by phone.
<p>Your telephone passcode
is: <span id="domain-registrar-phone-passcode">
{if (isNonnull($phonePasscode))}
{$phonePasscode}
{else}
<em>pending allocation</em>
{/if}
</span>
<p>Call us at:
<p id="registry-phone"><a href="tel:{$supportPhoneNumber}">{$supportPhoneNumber}</a>
</td>
</table>
</div>
{/template}
/** Resources and billing links. */
{template .resources}
{@param? driveFolderId: string}
{@param technicalDocsUrl: string}
<div id="domain-registrar-resources">
<h1>Resources &amp; billing</h1>
<p>
The registry system uses <strong>Google Drive</strong> to share
important documentation.
<h2><img src="/assets/images/folder.png">TLD information</h2>
<p>
Find onboarding FAQs &amp; technical documentation here:
<br><br>
<a class="{css('kd-button')} {css('kd-button-submit')}"
href="{$technicalDocsUrl}"
target="_blank" rel="noopener">View TLD information on Google Drive</a>
<h2><img src="/assets/images/folder.png">Billing details</h2>
<p>
Find information on all transaction activity behind your monthly invoices in this folder.
<p>
{if (isNonnull($driveFolderId))}
<a id="reg-resources-driveLink"
class="{css('kd-button')} {css('kd-button-submit')}"
href="https://drive.google.com/drive/folders/{$driveFolderId}"
target="_blank" rel="noopener">View billing details on Google Drive</a>
{else}
<em>Your billing folder is pending allocation.</em>
{/if}
</div>
{/template}
/** Loading page. */
{template .loading}
<img alt="[Loading...]" src="/assets/images/loader4x.gif" width="87" height="87">
{/template}

View File

@@ -1,166 +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.
{namespace registry.soy.console}
/**
* Common header fragment.
*/
{template .header}
{@param app: string} /** App identifier, e.g. 'admin', 'registrar'. */
{@param? subtitle: string} /** Extra stuff to put in {@code <title>}. */
{@param analyticsConfig: [googleAnalyticsId: string|null]}
<!doctype html>
<meta charset="utf-8">
{literal}<!--
CHARLESTON ROAD REGISTRY SHARED REGISTRATION SYSTEM
ICANN-GTLD-AGB-20120604
_____ _
| __ \ (_)
| | | | ___ _ __ ___ __ _ _ _ __
| | | |/ _ \| '_ ` _ \ / _` | | '_ \
| |__| | (_) | | | | | | (_| | | | | |
|_____/ \___/|_| |_| |_|\__,_|_|_| |_|
| __ \ (_) | |
| |__) |___ __ _ _ ___| |_ _ __ _ _
| _ // _ \/ _` | / __| __| '__| | | |
| | \ \ __/ (_| | \__ \ |_| | | |_| |
|_| \_\___|\__, |_|___/\__|_| \__, |
__/ | __/ |
|___/ |___/
-->{/literal}
<title>Nomulus {if isNonnull($subtitle)} - {$subtitle}{/if}</title>
<link rel="icon" href="/assets/images/ribbon_certified-64.png">
{switch DEBUG}
{case google.registry.ui.ConsoleDebug.PRODUCTION}
<link rel="stylesheet" href="/assets/css/{$app}_bin.css">
{case google.registry.ui.ConsoleDebug.DEBUG}
<link rel="stylesheet" href="/assets/css/{$app}_dbg.css">
{case google.registry.ui.ConsoleDebug.RAW}
<link rel="stylesheet"
href="/assets/sources/domain_registry/java/google/registry/ui/css/{$app}_imports_raw.css">
{default}
<!-- No DEBUG option set. -->
{/switch}
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Open+Sans:300">
{call registry.soy.analytics.googleAnalytics data="all" /}
{/template}
/**
* Happy little googley bar.
*/
{template .googlebar}
{@param username: string}
{@param logoutUrl: string}
{@param logoFilename: string}
{@param productName: string}
<div id="kd-googlebar" role="banner" lang="en-US">
<a class="{css('logo')}" href="/registrar">
<img src="/assets/images/{$logoFilename}" alt="{$productName}">
</a>
<div id="kd-search">
<input id="kd-searchfield"
name="kd-searchfield"
type="text"
placeholder="Search using format 'contact/id'"
x-webkit-speech>
<a id="kd-searchbutton"
class="{css('kd-button')} {css('kd-button-submit')}"
style="-webkit-user-select: none;">
<img width="21" height="21" alt="Search White"
src="/assets/images/icons/svg/search.svg">
</a>
</div>
<div class="{css('kd-butterbar')}">
<p>
<span class="{css('kd-butterbar-text')}"></span>{sp}
<a class="{css('kd-butterbar-dismiss')}">Dismiss</a>
</p>
</div>
<div id="kd-social" class="{css('kd-buttonbar')} {css('right')}">
<span class="{css('kd-name')} {css('mobile-hide')} {css('x-crush-hide')}">
{$username}{sp}
<a href="{$logoutUrl}" tabindex="-1">Sign out</a>
</span>
</div>
</div>
{/template}
/** Appbar add/back, edit/cancel appbar. */
{template .appbarButtons}
<button id="reg-app-btn-add"
type="button"
class="{css('kd-button')} {css('kd-button-submit')} {css('hidden')}">
Add</button>
<div id="reg-app-btns-edit" class="{css('hidden')}">
<button id="reg-app-btn-edit"
type="button"
class="{css('kd-button')} {css('kd-button-submit')}">
Edit</button>
<button id="reg-app-btn-back" type="button" class="{css('kd-button')}">
Back</button>
</div>
<div id="reg-app-btns-save" class="{css('hidden')}">
<button id="reg-app-btn-save"
type="button"
class="{css('kd-button')} {css('kd-button-submit')}">
Save</button>
<button id="reg-app-btn-cancel" type="button" class="{css('kd-button')}">
Cancel</button>
</div>
{/template}
/**
* Create button for domain, contact and host.
*/
{template .navCreateButton}
<a id="reg-create-button"
class="{css('kd-button')} {css('kd-button-action')} {css('kd-menubutton')}"
style="-webkit-user-select: none;">
<span class="{css('label')}">Create</span>
<span class="{css('kd-disclosureindicator')}"></span>
<ul class="{css('kd-menulist')}" style="top: 27px;">
<li class="{css('kd-menulistitem')}"
style="-webkit-user-select: none;"
id="reg-menu-domain-create">Domain
<li class="{css('kd-menulistitem')}"
style="-webkit-user-select: none;"
id="reg-menu-contact-create">Contact
<li class="{css('kd-menulistitem')}"
style="-webkit-user-select: none;"
id="reg-menu-host-create">Host
</ul>
</a>
{/template}
/**
* Legal notices included as footer.
*/
{template .footer}
<div class="{css('pageFooter')} {css('clearfix')}">
<ul class="{css('linklist')} {css('right')}">
<li>
<a href="https://www.registry.google/about/privacy.html">Privacy</a>
<li>
<a href="https://www.google.com/intl/en/policies/terms/">Terms</a>
</ul>
</div>
{/template}

View File

@@ -1,379 +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.
{namespace registry.soy.registrar.contacts}
/** Registrar contacts listing for view only. */
{template .set}
{@param contactsByType: legacy_object_map<string, ?>}
{let $possibleTypesLookup: [
['admin', 'Primary', 'Primary contact for general issues.'],
['billing', 'Billing', 'Contact for financial communications & invoices.'],
['tech', 'Technical', 'Contact for technical communications about the registry.'],
['legal', 'Legal', 'Contact for all legal communications.'],
['marketing', 'Marketing', 'Contact for registry promotions and campaigns.'],
['abuse', 'Abuse', 'Contact for abuse complaints.'],
['whois', 'WHOIS-Inquiry', 'Contact for inquiries about WHOIS accuracy.'],
['other', 'Other', 'Contact that is none of the above types']] /}
<div class="{css('set')}">
<h1>Contact settings</h1>
<table>
{for $type in $possibleTypesLookup}
{if isNonnull($contactsByType[$type[0]])}
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">{$type[1]}
{sp}contact{if length($contactsByType[$type[0]]) > 1}s{/if}</label>
<span class="{css('description')}">{$type[2]}</span>
</td>
<td id="{$type[0]}-contacts"
class="{css('info')} {css('summary')} {css('domain-registrar-contacts')}">
{for $c in $contactsByType[$type[0]]}
{call .contactInfoCompact}
{param namePrefix: 'contacts[' + index($c) + '].' /}
{param name: $c['name'] /}
{param emailAddress: $c['emailAddress'] /}
{param visibleInWhois:
($c['visibleInWhoisAsAdmin']
or $c['visibleInWhoisAsTech']
or $c['visibleInDomainWhoisAsAbuse']) /}
{param phoneNumber: $c['phoneNumber'] /}
{param faxNumber: $c['faxNumber'] /}
{/call}
{if (index($c) + 1) % 3 == 0}<br>{/if}
{/for}
</td>
{/if}
{/for}
</table>
</div>
{/template}
/** Compact readonly contact info view. */
{template .contactInfoCompact}
{@param namePrefix: string}
{@param name: string}
{@param emailAddress: string}
{@param visibleInWhois: bool}
{@param? phoneNumber: string}
{@param? faxNumber: string}
<div class="{css('domain-registrar-contact')}">
<div class="{css('domain-registrar-contact-name')}"
id="{$namePrefix}name">
{$name}
{if $visibleInWhois}
<i class="{css('domain-registrar-contact-visible-in-whois')}"
onmouseover="this.childNodes[0].style.visibility = 'visible'"
onmouseout="this.childNodes[0].style.visibility = 'hidden'">
<div class="{css('tooltip')}">
Visible in WHOIS <span class="{css('pointer')}"></span>
</div>
</i>
{/if}
</div>
{if isNonnull($phoneNumber)}
<div class="{css('domain-registrar-contact-phoneNumber')}"
id="{$namePrefix}phoneNumber">{$phoneNumber}</div>
{/if}
{if isNonnull($faxNumber)}
<div class="{css('domain-registrar-contact-faxNumber')}"
id="{$namePrefix}faxNumber">{$faxNumber} (Fax)</div>
{/if}
<div class="{css('domain-registrar-contact-emailAddress')}"
id="{$namePrefix}emailAddress">{$emailAddress}</div>
<a href="#contact-settings/{$emailAddress}">View/Edit</a>
</div>
{/template}
/** Registrar contact item page. */
{template .contact}
{@param namePrefix: string}
{@param item: legacy_object_map<string, ?>}
{@param actualTypesLookup: legacy_object_map<string, bool>}
{@param readonly: bool}
{@param? registryLockAllowedForRegistrar: bool}
<form name="item" class="{css('item')} {css('registrar')}">
<h1>Contact details</h1>
{call .contactInfo data="all"}
{param namePrefix: $namePrefix /}
{param item: $item /}
{param actualTypesLookup: $actualTypesLookup /}
{param readonly: $readonly /}
{param registryLockAllowedForRegistrar: $registryLockAllowedForRegistrar /}
{/call}
</form>
{/template}
/** Contact info for view and edit. */
{template .contactInfo}
{@param namePrefix: string}
{@param item: legacy_object_map<string, ?>}
{@param actualTypesLookup: legacy_object_map<string, bool>}
{@param? readonly: bool}
{@param? registryLockAllowedForRegistrar: bool}
{let $possibleTypesLookup: [
['admin', 'Primary', 'Primary contact for general issues.'],
['billing', 'Billing', 'Contact for financial communications & invoices.'],
['tech', 'Technical', 'Contact for technical communications about the registry.'],
['legal', 'Legal', 'Contact for all legal communications.'],
['marketing', 'Marketing', 'Contact for registry promotions and campaigns.'],
['abuse', 'Abuse', 'Contact for abuse complaints.'],
['whois', 'WHOIS-Inquiry', 'Contact for inquiries about WHOIS accuracy.']] /}
<div>
<table>
{call registry.soy.forms.inputFieldRow data="all"}
{param label: 'Name' /}
{param namePrefix: $namePrefix /}
{param name: 'name' /}
{/call}
{call registry.soy.forms.inputFieldRow data="all"}
{param label: 'Primary account email' /}
{param namePrefix: $namePrefix /}
{param name: 'emailAddress' /}
{param disabled: not $readonly and $item['emailAddress'] != null /}
{/call}
{if isNonnull($item['registryLockEmailAddress'])}
{call registry.soy.forms.inputFieldRow data="all"}
{param label: 'Registry lock email address' /}
{param namePrefix: $namePrefix /}
{param name: 'registryLockEmailAddress' /}
{param disabled: not $readonly /}
{param description: 'Address to which registry (un)lock confirmation emails will be ' +
'sent. This is not necessarily the account email address that is used for login.' /}
{/call}
{/if}
{call registry.soy.forms.inputFieldRow data="all"}
{param label: 'Phone' /}
{param namePrefix: $namePrefix /}
{param name: 'phoneNumber' /}
{/call}
{call registry.soy.forms.inputFieldRow data="all"}
{param label: 'Fax' /}
{param namePrefix: $namePrefix /}
{param name: 'faxNumber' /}
{/call}
{if $readonly}
{call .contactTypeSettingsView_}
{param item: $item /}
{param possibleTypesLookup: $possibleTypesLookup /}
{param actualTypesLookup: $actualTypesLookup /}
{/call}
{else}
{call .contactTypeSettingsEdit_}
{param item: $item /}
{param namePrefix: $namePrefix /}
{param possibleTypesLookup: $possibleTypesLookup /}
{param actualTypesLookup: $actualTypesLookup /}
{param registryLockAllowedForRegistrar: $registryLockAllowedForRegistrar /}
{/call}
{/if}
</table>
{if isNonnull($item['loginEmailAddress'])}
<input type="hidden" name="{$namePrefix}loginEmailAddress" value="{$item['loginEmailAddress']}">
{/if}
</div>
{/template}
/** @private */
{template .contactTypeSettingsView_ visibility="private"}
{@param item: legacy_object_map<string, ?>}
{@param possibleTypesLookup: list<list<string>>}
{@param actualTypesLookup: legacy_object_map<string, bool>}
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Contact type</label>
<td class="{css('setting')}">
<div class="{css('setting-item-list')}">
{for $type in $possibleTypesLookup}
{if $actualTypesLookup[$type[0]]}
<div>{$type[1]} contact</div>
{/if}
{/for}
</div>
</td>
<tr><td colspan="2"><hr></tr>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Show in WHOIS</label>
</td>
<td class="{css('setting')}">
<p class="{css('setting-item-list')}">
{let $visibleAsAdmin: $item['visibleInWhoisAsAdmin'] == true /}
{let $visibleAsTech: $item['visibleInWhoisAsTech'] == true /}
{let $visibleAsDomainAbuse: $item['visibleInDomainWhoisAsAbuse'] == true /}
{if (not $visibleAsAdmin) and (not $visibleAsTech) and (not $visibleAsDomainAbuse)}
<span class="{css('whois-not-visible')}">Not visible in WHOIS</span>
{else}
{if $visibleAsAdmin}Registrar Admin{/if}
{if $visibleAsAdmin and $visibleAsTech},{sp}{/if}
{if $visibleAsTech}Registrar Technical{/if}
{if $visibleAsTech}
{if $visibleAsDomainAbuse},{sp}{/if}
{elseif $visibleAsAdmin and $visibleAsDomainAbuse},{sp}{/if}
{if $visibleAsDomainAbuse}Domain Abuse{/if}
{/if}
{/template}
/** @private */
{template .contactTypeSettingsEdit_ visibility="private"}
{@param item: legacy_object_map<string, ?>}
{@param namePrefix: string}
{@param possibleTypesLookup: list<list<string>>}
{@param actualTypesLookup: legacy_object_map<string, bool>}
{@param? registryLockAllowedForRegistrar: bool}
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Contact type</label>
<span class="{css('description')}">
Subscribe this contact to the checked mailing lists.
</span>
</td>
<td class="{css('setting')}">
{call .contactCheckboxes_}
{param namePrefix: $namePrefix /}
{param possibleTypesLookup: $possibleTypesLookup /}
{param actualTypesLookup: $actualTypesLookup /}
{/call}
</tr>
{if $registryLockAllowedForRegistrar}
{let $placeholder: $item['registryLockAllowed'] ?
// If registry lock is allowed, there's already a password
'Contact support to reset password' :
// Otherwise, if not allowed, support must enable it
not $item['allowedToSetRegistryLockPassword'] ?
'Contact support to enable registry lock' : '' /}
{call registry.soy.forms.inputFieldRow data="all"}
{param label: 'Registry lock password:' /}
{param name: 'registryLockPassword' /}
{param disabled: not $item['allowedToSetRegistryLockPassword'] /}
{param isPassword: true /}
{param placeholder: $placeholder /}
{/call}
{if $item['allowedToSetRegistryLockPassword']}
<tr>
<td></td>
<td>
<a id="showOrHideRegistryLockPassword">Show password</a>
</td>
</tr>
{/if}
{/if}
<input type="hidden" name="{$namePrefix}allowedToSetRegistryLockPassword"
{if isNonnull($item['allowedToSetRegistryLockPassword'])}
value="{$item['allowedToSetRegistryLockPassword']}"
{else}
value="false"
{/if}
>
<tr>
<td colspan="2">
<hr>
</tr>
{call .whoisVisibleRadios_}
{param description: 'Show in Registrar WHOIS record as admin contact' /}
{param fieldName: $namePrefix + 'visibleInWhoisAsAdmin' /}
{param visible: $item['visibleInWhoisAsAdmin'] == true /}
{/call}
{call .whoisVisibleRadios_}
{param description: 'Show in Registrar WHOIS record as technical contact' /}
{param fieldName: $namePrefix + 'visibleInWhoisAsTech' /}
{param visible: $item['visibleInWhoisAsTech'] == true /}
{/call}
{call .whoisVisibleRadios_}
{param description:
'Show Phone and Email in Domain WHOIS Record as registrar abuse contact' +
' (per CL&D requirements)' /}
{param note:
'*Can only apply to one contact. Selecting Yes for this contact will' +
' force this setting for all other contacts to be No.' /}
{param fieldName: $namePrefix + 'visibleInDomainWhoisAsAbuse' /}
{param visible: $item['visibleInDomainWhoisAsAbuse'] == true /}
{/call}
{/template}
/** @private */
{template .whoisVisibleRadios_ visibility="private"}
{@param description: string}
{@param? note: string}
{@param fieldName: string}
{@param visible: bool}
<tr class="{css('kd-settings-pane-section')}">
<td>
<label for="{$fieldName}">{$description}</label>
{if $note}
<span class="{css('description')}">{$note}</span>
{/if}
</td>
<td class="{css('setting')}">
<label for="{$fieldName}">
<input
name="{$fieldName}"
id="{$fieldName}.true"
type="radio"
value="true"
{if $visible} checked{/if}>{sp}Yes
</label>
<label for="{$fieldName}">
<input
name="{$fieldName}"
id="{$fieldName}.false"
type="radio"
value="false"
{if not $visible} checked{/if}>{sp}No
</label>
</td>
{/template}
/** @private */
{template .contactCheckboxes_ visibility="private"}
{@param namePrefix: string}
{@param actualTypesLookup: legacy_object_map<string, bool>}
{@param possibleTypesLookup: list<list<string>>}
{for $type in $possibleTypesLookup}
{let $name: $namePrefix + 'type.' + $type[0] /}
{let $checked: $actualTypesLookup[$type[0]] /}
<div class="{css('checkbox-with-label')}">
<input type="checkbox"
name="{$name}"
id="{$name}"
{if $checked} checked{/if}>
<label for="{$name}">
{$type[1]} contact
<span class="{css('description')}">{$type[2]}</span>
</label>
</div>
{/for}
{/template}
/** IP address form input. */
{template .ip}
{@param name: string}
{@param ip: string}
<div class="{css('ip')}">
<input name="{$name}" value="{$ip}" readonly>
<button type="button" class="{css('kd-button')} {css('btn-remove')} {css('hidden')}">
<i class="{css('icon-remove')} {css('edit')}">x</i>
</button>
</div>
{/template}

View File

@@ -1,348 +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.
{namespace registry.soy.forms}
/**
* Input field.
*/
{template .inputField}
{@param name: ?} /** Input field name. */
{@param? item: ?} /** This will be used to set default value with $item[$name]. */
{@param? label: ?} /** Input field label. */
{@param? placeholder: ?} /** Placeholder text. */
<label for="{$name}">
{if isNonnull($label)}
{$label}
{else}
{$name}
{/if}
</label>
<input id="{$name}"
name="{$name}"
{if isNonnull($item) and isNonnull($item[$name])}
value="{$item[$name]}"
{/if}
{if isNonnull($placeholder)}
placeholder="{$placeholder}"
{/if}>
{/template}
/**
* Input field in a table row.
*/
{template .inputFieldRow}
{@param name: ?} /** Input field name. */
{@param? item: ?} /** This will be used to set default value with $item[$name]. */
{@param? itemPrefix: ?}
{@param? namePrefix: ?}
{@param? label: ?} /** Input field label. */
{@param? description: ?} /** Input field description. */
{@param? placeholder: ?} /** Placeholder text. */
{@param? readonly: ?}
{@param? disabled: ?}
{@param? isPassword: ?}
<tr class="{css('kd-settings-pane-section')}">
<td>
<label for="{if isNonnull($namePrefix)}{$namePrefix + $name}{else}{$name}{/if}"
class="{css('setting-label')}">
{if isNonnull($label)}
{$label}
{else}
{$name}
{/if}
</label>
{if isNonnull($description)}
<span class="{css('description')}">{$description}</span>
{/if}
</td>
<td class="{css('setting')}">
<input id="{if isNonnull($namePrefix)}{$namePrefix + $name}{else}{$name}{/if}"
name="{if isNonnull($namePrefix)}{$namePrefix + $name}{else}{$name}{/if}"
{if isNonnull($item)}
{if isNonnull($itemPrefix) and isNonnull($item[$itemPrefix + $name])}
value="{$item[$itemPrefix + $name]['keyValue'] ?: $item[$itemPrefix + $name]}"
{elseif isNonnull($item[$name])}
value="{$item[$name]['keyValue'] ?: $item[$name]}"
{/if}
{/if}
{if isNonnull($placeholder) and not $readonly}
placeholder="{$placeholder}"
{/if}
{if $readonly}
readonly
{/if}
{if $disabled}
disabled
{/if}
{if $isPassword}
type="password" minlength="8"
{/if}>
</td>
</tr>
{/template}
/* XXX: Should move other impls in this file to use this. */
/** Input field label. */
{template .inputFieldLabel}
{@param label: string}
{@param? forId: string}
{@param? description: string}
<label {if isNonnull($forId)}for="{$forId}"{/if} class="{css('setting-label')}">
{$label}
</label>
{if isNonnull($description)}
<span class="{css('description')}">{$description}</span>
{/if}
{/template}
/** Input field value. */
{template .inputFieldValue}
{@param name: string}
{@param? readonly: bool}
{@param? required: bool}
{@param? value: ?}
{@param? namePrefix: string}
{@param? placeholder: string}
{@param? clazz: string}
{@param? type: string}
{let $forId: isNonnull($namePrefix) ? $namePrefix + $name : $name /}
<input name="{$forId}"
id="{$forId}"
value="{if isNonnull($value)}{$value['keyValue'] ?: $value}{/if}"
{if isNonnull($clazz)}class="{$clazz}"{/if}
{if isNonnull($type)}type="{$type}"{/if}
{if isNonnull($placeholder) and not $readonly}
placeholder="{$placeholder}"
{/if}
{if $required}required{/if}
{if $readonly}readonly{/if}>
{/template}
/** Input field in a table row. */
{template .inputFieldRowWithValue}
{@param label: string}
{@param name: string}
{@param? readonly: bool}
{@param? required: bool}
{@param? namePrefix: string}
{@param? value: ?}
{@param? description: string}
{@param? placeholder: string}
{@param? clazz: string}
{@param? type: string}
{let $forId: isNonnull($namePrefix) ? $namePrefix + $name : $name /}
<tr class="{css('kd-settings-pane-section')}">
<td>
{call .inputFieldLabel data="all"}
{param forId: $forId /}
{/call}
</td>
<td class="{css('setting')}">
{call .inputFieldValue data="all" /}
</td>
</tr>
{/template}
/**
* Form input row for a table.
*/
{template .textareaFieldRow}
{@param name: ?} /** Input field name. */
{@param? item: ?} /** This will be used to set default value with $item[$name]. */
{@param? itemPrefix: ?}
{@param? namePrefix: ?}
{@param? label: ?} /** Input field label. */
{@param? readonly: ?}
<tr>
<td>
<label for="{if isNonnull($namePrefix)}{$namePrefix + $name}{else}{$name}{/if}">
{if isNonnull($label)}
{$label}
{else}
{$name}
{/if}
</label>
</td>
<td>
<textarea id="{$name}"
name="{if isNonnull($namePrefix)}{$namePrefix + $name}{else}{$name}{/if}"
{if $readonly}
readonly
{/if}
>{if isNonnull($item)}
{if isNonnull($itemPrefix) and isNonnull($item[$itemPrefix + $name])}
{$item[$itemPrefix + $name]}
{elseif isNonnull($item[$name])}
{$item[$name]}
{/if}
{/if}</textarea>
</td>
</tr>
{/template}
/**
* Form input row for a table.
*/
{template .textareaFieldRowWithValue}
{@param name: ?} /** Input field name. */
{@param value: ?}
{@param? namePrefix: ?}
{@param? label: ?} /** Input field label. */
{@param? readonly: ?}
<tr>
<td>
<label for="{if isNonnull($namePrefix)}{$namePrefix + $name}{else}{$name}{/if}">
{if isNonnull($label)}
{$label}
{else}
{$name}
{/if}
</label>
</td>
<td>
<textarea id="{$name}"
name="{if isNonnull($namePrefix)}{$namePrefix + $name}{else}{$name}{/if}"
{if $readonly}
readonly
{/if}
>{if isNonnull($value) and isNonnull($value['keyValue'])}
{$value['keyValue']}
{/if}</textarea>
</td>
</tr>
{/template}
/**
* Select control.
*/
{template .selectRow}
{@param name: ?} /** Input field name. */
{@param options: ?} /** Items listed in the selector. */
{@param selected: ?} /** Name of the selected option. */
{@param? namePrefix: ?}
{@param? label: ?} /** Input field label. */
{@param? readonly: ?}
{let $forId: isNonnull($namePrefix) ? $namePrefix + $name : $name /}
<tr>
<td>
<label for="{$forId}">
{if isNonnull($label)}
{$label}
{else}
{$name}
{/if}
</label>
</td>
<td>
<select id="{$name}"
name="{$name}"
class="{css('kd-button')} {css('reg-select')}"
{if $readonly}disabled{/if}>
{for $option in $options}
<option value="{$option}" {if $selected == $option}selected{/if}>
{$option}
</option>
{/for}
</select>
</td>
</tr>
{/template}
{template .inputRadioWithValue}
{@param name: ?}
{@param values: ?}
{@param? checkedValue: ?} /** the default checked value. */
<tr>
<td colspan="2">
{for $value in $values}
<input type="radio"
name="{$name}"
value="{$value}"
{if $checkedValue == $value}checked{/if}>
{/for}
</td>
</tr>
{/template}
/** Checkbox with label. */
{template .inputCheckboxRow}
{@param name: string}
{@param? checked: bool}
{@param? label: string}
{@param? description: string}
<tr>
<td>
{call .inputFieldLabel data="all"}
{param label: $label ? $label : $name /}
{param forId: $name /}
{/call}
</td>
<td>
<input id="{$name}"
type="checkbox"
name="{$name}"
value="{$name}"
{if isNonnull($checked) and $checked}checked{/if}>
</td>
</tr>
{/template}
/** Submit button. */
{template .submitRow}
{@param label: string}
<tr>
<td></td>
<td>
<input
id="submit-button"
type="submit"
value="{$label}"
class="{css('kd-button')} {css('kd-button-submit')}">
</td>
</tr>
{/template}
/** Drop-down select button widget. */
{template .menuButton}
{@param id: string} /** ID for button. */
{@param selected: string} /** Selected item. */
{@param items: list<string>} /** Selectable items. */
<div id="{$id}" class="{css('kd-button')} {css('kd-menubutton')} {css('kd-select')}">
<span class="{css('label')}">
{$selected}
</span>
<span class="{css('kd-disclosureindicator')}"></span>
<ul class="{css('kd-menulist')}">
{for $item in $items}
<li class="{css('kd-menulistitem')}
{if $item == $selected}
{sp}{css('selected')}
{/if}">
{$item}
{/for}
</ul>
</div>
{/template}

View File

@@ -1,197 +0,0 @@
// Copyright 2018 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.
{namespace registry.soy.registrar.otesetup}
/**
* Main page for the OT&amp;E creation. Holds a form with the required data.
*/
{template .formPage}
{@param xsrfToken: string} /** Security token. */
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param productName: string} /** Name to display for this software product. */
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{@param logoFilename: string}
{@param? errorMessage: string} /** If set - display the error message above the form. */
{@param? baseClientId: string} /** If set - an initial value to fill for the base client ID. */
{@param? contactEmail: string} /** If set - an initial value to fill for the email. */
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'OT&E setup' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
{call registry.soy.console.googlebar data="all" /}
<div id="reg-content-and-footer">
<div id="reg-content">
<h1>Setup OT&E</h1>
{if isNonnull($errorMessage)}
<h2 class="{css('kd-errormessage')}">Failed: {$errorMessage}</h2>
{/if}
{call .form_ data="all" /}
</div>
{call registry.soy.console.footer /}
</div>
{/template}
/**
* Result page for a successful OT&amp;E setup.
*/
{template .resultSuccess}
{@param baseClientId: string} /** The base clientId used for the OT&amp;E setup. */
{@param contactEmail: string} /** The contact's email added to the registrars. */
{@param clientIdToTld: map<string, string>} /** The created registrars-&gt;TLD mapping. */
{@param password: string} /** The password given for the created registrars. */
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param productName: string} /** Name to display for this software product. */
{@param logoFilename: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'OT&E setup' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
{call registry.soy.console.googlebar data="all" /}
<div id="reg-content-and-footer">
<div id="reg-content" class="{css('item')} {css('registrar')}">
<h1>OT&E successfully created for registrar {$baseClientId}!</h1>
<table>
<tr>
<td>
<label class="{css('setting-label')}">EPP credentials</label>
<span class="{css('description')}">Copy and paste this into an email to the registrars</span>
</td>
<td class="{css('setting')}">
<textarea rows="7" cols="100" spellcheck="false" readonly>
{for $clientId in mapKeys($clientIdToTld)}
Login: {$clientId}{sp}{sp}{sp}{sp}{sp}{sp}
Password: {$password}{sp}{sp}{sp}{sp}{sp}{sp}
TLD: {$clientIdToTld[$clientId]}{sp}{sp}{sp}{sp}{sp}{sp}{\n}
{/for}
</textarea>
</td>
</table>
Gave <label>{$contactEmail}</label> web-console access to these registrars.
<h1>Don't forget to set the <label>Certificate</label> and <label>IP allow list</label> for these Registrars!</h1>
Links to the security page for your convenience:<br>
{for $clientId in mapKeys($clientIdToTld)}
<a href="/registrar?clientId={$clientId}#security-settings" target="_blank">{$clientId}</a><br>
{/for}
</div>
{call registry.soy.console.footer /}
</div>
{/template}
/** Form for getting registrar info. */
{template .form_ visibility="private"}
{@param xsrfToken: string} /** Security token. */
{@param? baseClientId: string} /** If set - an initial value to fill for the base client ID. */
{@param? contactEmail: string} /** If set - an initial value to fill for the email. */
<form name="item" class="{css('item')}" method="post" action="/registrar-ote-setup">
<table>
<tr class="{css('kd-settings-pane-section')}">
<td>
{call registry.soy.forms.inputFieldLabel}
{param label: 'Base client ID' /}
{/call}
</td>
<td class="{css('setting')}">
{call registry.soy.forms.inputFieldValue }
{param name: 'clientId' /}
{param value: $baseClientId /}
{param placeholder: 'registrar\'s ID' /}
{param required: true /}
{/call}
<span class="{css('description')}">
Must consist of 3-14 lower-case letters and numbers.
</span>
</td>
</tr>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Contact email' /}
{param name: 'email' /}
{param value: $contactEmail /}
{param placeholder: 'registrar\'s assigned email' /}
{param description kind="text"}
Will be granted web-console access to the OTE registrars.
{/param}
{param required: true /}
{/call}
<tr>
<td colspan="2">
<hr>
<h1>Optional fields</h1>
Don't fill unless you have a good reason to.
</td>
</tr>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'EPP password' /}
{param name: 'password' /}
{param placeholder: 'Optional' /}
{param description kind="text"}
The password used to for EPP login. Leave blank to auto-generate.
{/param}
{/call}
{call registry.soy.forms.submitRow}
{param label: 'create' /}
{/call}
</table>
<input type="hidden" name="xsrfToken" value="{$xsrfToken}">
</form>
{/template}
/**
* Who goes thar?!
*/
{template .whoareyou}
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param logoFilename: string}
{@param productName: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Not Authorized' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
<div class="{css('whoAreYou')}">
<a class="{css('logo')}" href="/registrar">
<img src="/assets/images/{$logoFilename}" alt="{$productName}">
</a>
<h1>You need permission</h1>
<p>
Only {$productName} Admins have access to this page.
You are signed in as <strong>{$username}</strong>.
<div>
<a href="{$logoutUrl}"
class="{css('kd-button')} {css('kd-button-submit')}"
tabindex="-1">Logout and switch to another account</a>{sp}
<a href="/registrar"
class="{css('kd-button')} {css('kd-button-submit')}"
tabindex="-1">Go to the Registrar web console</a>
</div>
</div>
{/template}

View File

@@ -1,369 +0,0 @@
// Copyright 2018 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.
{namespace registry.soy.registrar.registrarcreate}
/**
* Main page for the registrar creation. Holds a form with the required data.
*/
{template .formPage}
{@param xsrfToken: string} /** Security token. */
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param productName: string} /** Name to display for this software product. */
{@param logoFilename: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{@param? errorMessage: string} /** If set - display the error message above the form. */
{@param? clientId: string} /** If set - an initial value for the client ID. */
{@param? name: string} /** If set - an initial value for the Registrar name. */
{@param? billingAccount: string} /** If set - the billing accounts data. */
{@param? ianaId: int} /** If set - an initial value for the IANA ID. */
{@param? referralEmail: string} /** If set - an initial value for the ICANN referral email. */
{@param? driveId: string} /** If set - an initial value for the DRIVE ID. */
{@param? consoleUserEmail: string} /** If set - the user to be given console access. */
{@param? street1: string} /** If set - the first line of the street address. */
{@param? street2: string} /** If set - the second line of the street address. */
{@param? street3: string} /** If set - the third line of the street address. */
{@param? city: string} /** If set - the address city. */
{@param? state: string} /** If set - the state/region of the address. */
{@param? countryCode: string} /** If set - the 2 letter country code. */
{@param? zip: string} /** If set - the zip code of the address. */
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Create Registrar' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
{call registry.soy.console.googlebar data="all" /}
<div id="reg-content-and-footer">
<div id="reg-content">
<h1>Create Registrar</h1>
{if isNonnull($errorMessage)}
<h2 class="{css('kd-errormessage')}">Failed: {$errorMessage}</h2>
{/if}
{call .form_ data="all" /}
</div>
{call registry.soy.console.footer /}
</div>
{/template}
/**
* Result page for a successful registrar creation.
*/
{template .resultSuccess}
{@param clientId: string} /** The clientId of the registrar. */
{@param consoleUserEmail: string} /** The email of the account with web access to the registrar. */
{@param passcode: string} /** The phone passcode for this registrar. */
{@param password: string} /** The password given for the created registrars. */
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param productName: string} /** Name to display for this software product. */
{@param logoFilename: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Create Registrar' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
{call registry.soy.console.googlebar data="all" /}
<div id="reg-content-and-footer">
<div id="reg-content" class="{css('item')} {css('registrar')}">
<h1>Successfully created Registrar {$clientId}</h1>
<table>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Client ID' /}
{param name: 'clientId' /}
{param value: $clientId /}
{param description kind="text"}
The registrar's Client ID
{/param}
{param readonly: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'EPP password' /}
{param name: 'password' /}
{param value: $password /}
{param description kind="text"}
The password used to for EPP login.
{/param}
{param readonly: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Phone passcode' /}
{param name: 'passcode' /}
{param value: $passcode /}
{param description kind="text"}
Passcode used for phone authentication.
{/param}
{param readonly: true /}
{/call}
<tr>
<td>
<label class="{css('setting-label')}">Registrar credentials</label>
<span class="{css('description')}">Copy and paste this into an email to the registrars</span>
</td>
<td class="{css('setting')}">
<textarea rows="5" cols="30" spellcheck="false" readonly>
Login: {$clientId}{\n}
Password: {$password}{\n}
Phone passcode: {$passcode}{\n}
</textarea>
</td>
</table>
Gave <label>{$consoleUserEmail}</label> web-console access to this registrar.
<h1>You may want to set additional values using the web console:</h1>
<span class="{css('description')}">
<ol type="1">
<li>phone number, email, URL on the {sp}
<a href="/registrar?clientId={$clientId}#whois-settings" target="_blank">WHOIS page</a>
<li>allowed TLDs on the {sp}
<a href="/registrar?clientId={$clientId}#admin-settings" target="_blank">admin page</a>
<li>certificate, IP allow list on the {sp}
<a href="/registrar?clientId={$clientId}#security-settings" target="_blank">security page</a>
</ol>
</span>
</div>
{call registry.soy.console.footer /}
</div>
{/template}
/** Form for getting registrar info. */
{template .form_ visibility="private"}
{@param xsrfToken: string} /** Security token. */
{@param? clientId: string} /** If set - an initial value for the client ID. */
{@param? name: string} /** If set - an initial value for the Registrar name. */
{@param? billingAccount: string} /** If set - the billing accounts data. */
{@param? ianaId: int} /** If set - an initial value for the IANA ID. */
{@param? referralEmail: string} /** If set - an initial value for the ICANN referral email. */
{@param? driveId: string} /** If set - an initial value for the DRIVE ID. */
{@param? consoleUserEmail: string} /** If set - the user to be given console access. */
{@param? street1: string} /** If set - the first line of the street address. */
{@param? street2: string} /** If set - the second line of the street address. */
{@param? street3: string} /** If set - the third line of the street address. */
{@param? city: string} /** If set - the address city. */
{@param? state: string} /** If set - the state/region of the address. */
{@param? countryCode: string} /** If set - the 2 letter country code. */
{@param? zip: string} /** If set - the zip code of the address. */
<form name="item" class="{css('item')}" method="post" action="/registrar-create">
<table>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Name' /}
{param name: 'name' /}
{param value: $name /}
{param placeholder: 'required' /}
{param description kind="text"}
Name of the registrar.
{/param}
{param required: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Client ID' /}
{param name: 'clientId' /}
{param value: $clientId /}
{param placeholder: 'required' /}
{param description kind="text"}
Client identifier of the registrar account.
{/param}
{param required: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Registrar Console Username' /}
{param name: 'consoleUserEmail' /}
{param value: $consoleUserEmail /}
{param placeholder: 'required' /}
{param description kind="text"}
The email we created for the registrar.
Will be granted web-console access to the registrar.
{/param}
{param required: true /}
{/call}
<tr class="{css('kd-settings-pane-section')}">
<td>
{call registry.soy.forms.inputFieldLabel}
{param label: 'Billing accounts' /}
{param description kind="text"}
Registrar billing account IDs.
Each currency in a separate line in the format
[currency]=[account ID].
{/param}
{/call}
</td>
<td class="{css('setting')}">
<textarea
name="billingAccount"
id="billingAccount"
rows="4"
cols="50"
placeholder=
"Example:{\n}
USD=billing-id-for-usd{\n}
JPY=billing-id-for-yen{\n}"
spellcheck="false"
required>{$billingAccount ?: ''}</textarea>
</td>
</tr>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'IANA ID' /}
{param name: 'ianaId' /}
{param value: $ianaId /}
{param placeholder: 'required' /}
{param type: 'number' /}
{param description kind="text"}
Registrar IANA ID.
{/param}
{param required: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'ICANN referral email' /}
{param name: 'referralEmail' /}
{param value: $referralEmail /}
{param placeholder: 'required' /}
{param description kind="text"}
ICANN referral email, as specified in registrar contract.
{/param}
{param required: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Drive ID' /}
{param name: 'driveId' /}
{param value: $driveId /}
{param placeholder: 'required' /}
{param description kind="text"}
ID (not full URL) of this registrar's folder in Google Drive.
{/param}
{param required: true /}
{/call}
<tr>
<td colspan="2">
<hr>
<h1>Contact Info</h1>
</td>
</tr>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Street address' /}
{param name: 'street1' /}
{param value: $street1 /}
{param placeholder: 'required' /}
{param required: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: '' /}
{param name: 'street2' /}
{param value: $street2 /}
{param placeholder: 'optional' /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: '' /}
{param name: 'street3' /}
{param value: $street3 /}
{param placeholder: 'optional' /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'City' /}
{param name: 'city' /}
{param value: $city /}
{param placeholder: 'required' /}
{param required: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'State/region' /}
{param name: 'state' /}
{param value: $state /}
{param placeholder: 'optional' /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Zip/postal code' /}
{param name: 'zip' /}
{param value: $zip /}
{param placeholder: 'optional' /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Country Code (e.g. US)' /}
{param name: 'countryCode' /}
{param value: $countryCode /}
{param placeholder: 'required' /}
{param required: true /}
{/call}
<tr>
<td colspan="2">
<hr>
<h1>Optional fields</h1>
Don't fill unless you have a good reason to.
</td>
</tr>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'EPP password' /}
{param name: 'password' /}
{param placeholder: 'optional' /}
{param description kind="text"}
The password used to for EPP login. Leave blank to auto-generate.
{/param}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Phone passcode' /}
{param name: 'passcode' /}
{param placeholder: 'optional' /}
{param description kind="text"}
The passcode used for phone authentication. Leave blank to auto-generate.
{/param}
{/call}
{call registry.soy.forms.submitRow}
{param label: 'create' /}
{/call}
</table>
<input type="hidden" name="xsrfToken" value="{$xsrfToken}">
</form>
{/template}
/**
* Who goes thar?!
*/
{template .whoareyou}
{@param username: string} /** Arbitrary username to display. */
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
{@param logoFilename: string}
{@param productName: string}
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Not Authorized' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
<div class="{css('whoAreYou')}">
<a class="{css('logo')}" href="/registrar">
<img src="/assets/images/{$logoFilename}" alt="{$productName}">
</a>
<h1>You need permission</h1>
<p>
Only {$productName} Admins have access to this page.
You are signed in as <strong>{$username}</strong>.
<div>
<a href="{$logoutUrl}"
class="{css('kd-button')} {css('kd-button-submit')}"
tabindex="-1">Logout and switch to another account</a>{sp}
<a href="/registrar"
class="{css('kd-button')} {css('kd-button-submit')}"
tabindex="-1">Go to the Registrar web console</a>
</div>
</div>
{/template}

View File

@@ -1,169 +0,0 @@
// 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.
{namespace registry.soy.registrar.registrylock}
/** Registry locks viewing, adding, and removing. */
{template .settings}
<h1>Registry lock</h1>
<br>
<div id="locks-content">
// CSS-ified loading spinner
<div class="{css('lds-ring')}">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
{/template}
{template .locksContent}
{@param email: string}
{@param locks: list<[domainName: string, lockedTime: string, lockedBy: string,
userCanUnlock: bool, isLockPending: bool, isUnlockPending: bool]>}
{@param lockEnabledForContact: bool}
{call .newLock}
{param email: $email /}
{param lockEnabledForContact: $lockEnabledForContact /}
{/call}
{call .existingLocksTable}
{param locks: $locks /}
{param lockEnabledForContact: $lockEnabledForContact /}
{/call}
{/template}
{template .newLock}
{@param email: string}
{@param lockEnabledForContact: bool}
<div class="{css('new-registry-lock')}">
{if $lockEnabledForContact}
<h2>Lock a domain</h2>
<br>
<p>The lock will not take effect until you click the confirmation link that will be emailed to
you at {$email}. When it takes effect, you will be billed the standard server status change
billing cost.</p>
<button id="button-lock-domain"
{if $lockEnabledForContact}
class="{css('kd-button')} {css('kd-button-submit')}"
{else}
class="{css('kd-button')}" disabled
{/if}
>Lock a new domain
</button>
{else}
<h2>You are not permitted to change registry locks.</h2>
{/if}
<br><br>
</div>
{/template}
/** Table that displays existing locks for this registrar. */
{template .existingLocksTable}
{@param locks: list<[domainName: string, lockedTime: string, lockedBy: string,
userCanUnlock: bool, isLockPending: bool, isUnlockPending: bool]>}
{@param lockEnabledForContact: bool}
<h2>Existing locks</h2>
<br>
<table class="{css('registry-locks-table')}">
<tr>
<th><b>Domain name</b></th>
<th><b>Date/time locked</b></th>
<th><b>Locked by</b></th>
<th><b>Actions</b></th>
</tr>
{for $lock in $locks}
<tr class="{css('registry-locks-table-row')}">
<td>{$lock.domainName}
{if $lock.isLockPending}<i> (pending)</i>
{elseif $lock.isUnlockPending}<i> (unlock pending)</i>
{/if}</td>
<td>{$lock.lockedTime}</td>
<td>{$lock.lockedBy}</td>
<td>
{if not $lock.isLockPending and not $lock.isUnlockPending}
<button id="button-unlock-{$lock.domainName}"
{if $lockEnabledForContact and $lock.userCanUnlock}
class="domain-unlock-button {css('kd-button')} {css('kd-button-submit')}"
{else}
class="{css('kd-button')}"
disabled
{/if}
>Unlock
</button>
{/if}
</td>
</tr>
{/for}
</table>
{/template}
/** Modal that confirms that the user wishes to lock/unlock a domain. */
{template .confirmModal}
{@param isLock: bool}
{@param isAdmin: bool}
{@param emailAddress: string}
{@param? domain: string|null}
<div id="lock-confirm-modal" class="{css('lock-confirm-modal')}">
<div class="modal-content">
<p>Are you sure you want to {if $isLock}lock a domain{else}unlock the domain {$domain}{/if}?
We will send an email to {$emailAddress} to confirm the {if not $isLock}un{/if}lock.</p>
<label for="domain-to-lock">Domain: </label>
<input id="domain-lock-input-value"
{if isNonnull($domain)}
value="{$domain}" disabled
{/if}>
<br>
{if not $isAdmin}
<label for="domain-lock-password">Registry lock password: </label>
<input type="password" id="domain-lock-password">
<br>
{/if}
{if not $isLock}
<div>
<br>
<p>Automatically re-lock the domain after:</p>
<input type="radio" name="relock-duration" id="one-hour-duration" value="3600000"
class="relock-duration-input">
<label for="one-hour-duration">1 hour</label><br>
<input type="radio" name="relock-duration" id="six-hour-duration" value="21600000"
class="relock-duration-input" checked>
<label for="six-hour-duration">6 hours</label><br>
<input type="radio" name="relock-duration" id="twenty-four-hour-duration" value="86400000"
class="relock-duration-input">
<label for="twenty-four-hour-duration">24 hours</label><br>
<input type="radio" name="relock-duration" id="never-relock-duration" value="0"
class="relock-duration-input">
<label for="never-relock-duration">Never</label><br>
</div>
{/if}
<div id="modal-error-message" hidden class="{css('kd-errormessage')}"></div>
<div class="{css('buttons-div')}">
<button id="domain-lock-cancel" class="{css('kd-button')}">Cancel</button>
<button id="domain-lock-submit"
class="{css('kd-button')} {css('kd-button-submit')}">Submit
</button>
</div>
</div>
</div>
{/template}
/** Content if the registrar is not allowed to use registry lock. */
{template .lockNotAllowedOnRegistrar}
{@param supportEmail: string}
<h2>Sorry, your registrar hasn't enrolled in registry lock yet. To do so, please
contact {$supportEmail}.</h2>
{/template}

View File

@@ -1,71 +0,0 @@
// Copyright 2019 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.
{namespace registry.soy.registrar.registrylock.verification}
/**
* Results page for a registry lock/unlock verification.
*/
{template .verificationPage}
{@param username: string} /** Arbitrary username to display. */
{@param analyticsConfig: [googleAnalyticsId: string|null]}
{@param success: bool}
{@param? errorMessage: string}
{@param? isLock: bool}
{@param? domainName: string}
{call registry.soy.console.header}
{param app: 'registrar' /}
{param subtitle: 'Verify Registry Lock' /}
{param analyticsConfig: $analyticsConfig /}
{/call}
{call registry.soy.console.googlebar data="all" /}
<div id="reg-content-and-footer">
<div id="reg-content">
<h1>Registry Lock Verification</h1>
{if $success}
{call .success data="all" /}
{else}
{call .failure data="all" /}
{/if}
<h3><a href="/registrar">Return to Registrar Console</a></h3>
</div>
{call registry.soy.console.footer /}
</div>
{/template}
/**
* Result page for failure, e.g. the UUID was invalid
*/
{template .failure}
{@param? errorMessage: string}
<h2 class="{css('kd-errormessage')}">Failed: {if isNonnull($errorMessage)}
{$errorMessage}
{else}
Undefined error message
{/if}
</h2>
{/template}
/**
* Result page for a successful lock / unlock.
*/
{template .success}
{@param? isLock: bool}
{@param? domainName: string}
<h3>
Success: {if $isLock}lock{else}unlock{/if} has been applied to {$domainName}
</h3>
{/template}

View File

@@ -1,184 +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.
{namespace registry.soy.registrar.security}
/** Registrar security settings page for view and edit. */
{template .settings}
{@param ipAddressAllowList: list<string>}
{@param? phonePasscode: string}
{@param? clientCertificate: string}
{@param? clientCertificateHash: string}
{@param? failoverClientCertificate: string}
{@param readonly: bool}
<form name="item" class="{css('item')} {css('registrar')}">
<h1>Security settings</h1>
<table>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Web console access</label>
<td class="{css('setting')}">
<p>Your web console account is managed through&nbsp;
<a href="https://www.google.com/accounts"
target="_blank" rel="noopener">Google account settings</a>.
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">IP allow list</label>
<span class="{css('description')}">Restrict access to EPP
production servers to the following IP/IPv6 addresses, or
ranges like 1.1.1.0/24</span>
</td>
<td class="{css('setting')}">
<div class="{css('info')} {css('summary')}">
<div id="ips">
{for $ip in $ipAddressAllowList}
{call .ip}
{param name: 'ipAddressAllowList[' + index($ip) + ']' /}
{param ip: $ip /}
{/call}
{/for}
</div>
<div class="{css('hidden')}">
<input id="newIp" value="" placeholder="Enter IP address..."/>
<button id="btn-add-ip" type="button"
class="{css('kd-button')} {css('btn-add')}">Add</button>
</div>
</div>
</td>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">Telephone passcode</label>
<span class="{css('description')}">Use this for support calls to the Registry.</span>
</td>
<td class="{css('setting')}">
<div id="domain-registrar-phone-passcode">
{if isNonnull($phonePasscode)}
<input id="phonePasscode"
name="phonePasscode"
value="{$phonePasscode}" readonly>
{else}
<p><em>Your phone passcode is pending allocation.</em>
{/if}
</div>
</td>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">SSL Certificate</label>
<span class="{css('description')}">X.509 PEM certificate for EPP production access.</span>
</td>
<td class="{css('setting')}">
{if isNonnull($clientCertificate)}
<textarea
name="clientCertificate"
rows="16"
cols="68"
spellcheck="false"
{if $readonly}readonly{/if}>{$clientCertificate}</textarea>
{elseif isNonnull($clientCertificateHash)}
{if $readonly}
<p>
You submitted your SSL certificate before full certificates
were stored. Currently only the hash of your certificate may
be viewed. Please re-submit or update your certificate by
using the Edit button on the top of this page.
<p class="{css('certhash')}">
<span class="{css('description')}">Existing certificate SHA256 base64 hash:</span>
{$clientCertificateHash}
{else}
<textarea name="clientCertificate" rows="16" cols="68" spellcheck="false"></textarea>
{/if}
{else}
{if $readonly}
<p>No certificate on file. Use the Edit button on the top of this page to add one.
{else}
<p>No certificate on file. Please enter your certificate below.
<textarea id="clientCertificate"
name="clientCertificate"
rows="16" cols="68"
spellcheck="false"></textarea>
<div class="{css('description')}">
Example format:
<textarea id="exampleCert" rows="17" cols="68" spellcheck="false" readonly>
-----BEGIN CERTIFICATE-----{\n}
MIIDvTCCAqWgAwIBAgIJAK/PgPT0jTwRMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV{\n}
BAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazERMA8GA1UEBwwITmV3IFlvcmsxDzAN{\n}
BgNVBAoMBkdvb2dsZTEdMBsGA1UECwwUZG9tYWluLXJlZ2lzdHJ5LXRlc3QxEDAO{\n}
BgNVBAMMB2NsaWVudDEwHhcNMTUwODI2MTkxODA4WhcNNDMwMTExMTkxODA4WjB1{\n}
MQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZ{\n}
b3JrMQ8wDQYDVQQKDAZHb29nbGUxHTAbBgNVBAsMFGRvbWFpbi1yZWdpc3RyeS10{\n}
ZXN0MRAwDgYDVQQDDAdjbGllbnQxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB{\n}
CgKCAQEAvoE/IoFJyzb0dU4NFhL8FYgy+B/GnUd5aA66CMx5xKRMbEAtIgxU8TTO{\n}
W+9jdTsE00Grk3Ct4KdY73CYW+6IFXL4O0K/m5S+uajh+I2UMVZJV38RAIqNxue0{\n}
Egv9M4haSsCVIPcX9b+6McywfYSF1bzPb2Gb2FAQO7Jb0BjlPhPMIROCrbG40qPg{\n}
LWrl33dz+O52kO+DyZEzHqI55xH6au77sMITsJe+X23lzQcMFUUm8moiOw0EKrj/{\n}
GaMTZLHP46BCRoJDAPTNx55seIwgAHbKA2VVtqrvmA2XYJQA6ipdhfKRoJFy8Z8H{\n}
DYsorGtazQL2HhF/5uJD25z1m5eQHQIDAQABo1AwTjAdBgNVHQ4EFgQUParEmiSR{\n}
U/Oqy8hr7k+MBKhZwVkwHwYDVR0jBBgwFoAUParEmiSRU/Oqy8hr7k+MBKhZwVkw{\n}
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAojsUhF6PtZrStnHBFWNR{\n}
ryzvANB8krZlYeX9Hkqn8zIVfAkpbVmL8aZQ7yj17jSpw47PQh3x5gwA9yc/SS0G{\n}
E1rGuxYH02UGbua8G0+vviSQfLtskPQzK7EIR63WNhHEo/Q9umLJkZ0LguWEBf3L{\n}
q8CoXv2i/RNvqVPcTNp/zCKXJZAa8wAjNRJs834AZj4k5xwyYZ3F8D5PGz+YMOmV{\n}
M9Qd+NdXSC/Qn7HQzFhE8p5elBV35P8oX5dXEfn0S7zOXDenp5JvvLoggOWOcKsq{\n}
KiWDQrsT+TMKmHL94/h4t7FghtQLMzY5SGYJsYTv/LG8tewrz6KRb/Wj3JNojyEw{\n}
Ug=={\n}
-----END CERTIFICATE-----
</textarea>
</div>
{/if}
{/if}
</td>
<tr class="{css('kd-settings-pane-section')}">
<td>
<label class="{css('setting-label')}">
Failover SSL Certificate
</label>
<span class="{css('description')}">
X.509 PEM backup certificate for EPP Production Access.
</span>
<td class="{css('setting')}">
{if $readonly and not isNonnull($failoverClientCertificate)}
<p>No failover certificate on file.
{else}
<textarea id="failoverClientCertificate"
name="failoverClientCertificate"
rows="16"
cols="68"
spellcheck="false"
{if $readonly}readonly{/if}>
{$failoverClientCertificate ?: ''}
</textarea>
{/if}
</table>
</form>
{/template}
/** IP address form input. */
{template .ip}
{@param name: string}
{@param ip: string}
<div class="{css('ip')}">
<button type="button" class="{css('kd-button')} {css('btn-remove')} {css('hidden')}">
<i class="{css('icon-remove')} {css('edit')}">x</i>
</button>
<input name="{$name}" value="{$ip}" readonly>
</div>
{/template}

View File

@@ -1,232 +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.
{namespace registry.soy.registrar.whois}
/** Registrar whois settings page for view and edit. */
{template .settings}
{@param registrarId: string}
{@param? ianaIdentifier: int}
{@param? icannReferralEmail: string}
{@param readonly: bool}
{@param? whoisServer: string}
{@param? url: string}
// Passed to .contactInfo_
{@param? emailAddress: string}
{@param? localizedAddress: ?}
{@param? phoneNumber: string}
{@param? faxNumber: string}
{let $whoisServerNonNull: $whoisServer ?: 'None' /}
{let $urlNonNull: $url ?: 'None' /}
<form name="item" class="{css('item')} {css('registrar')} {css('kd-settings-pane')}">
<h1>WHOIS settings</h1>
{if $readonly}
<p>General registrar information for your WHOIS record. This
information is always visible in WHOIS.
{/if}
<table>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Name' /}
{param name: 'registrarId' /}
{param value: $registrarId /}
{param readonly: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'IANA ID' /}
{param name: 'ianaIdentifier' /}
{param value: $ianaIdentifier /}
{param readonly: true /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'ICANN referral email' /}
{param name: 'icannReferralEmail' /}
{param value: $icannReferralEmail /}
{param readonly: true /}
{/call}
{call .contactInfo_ data="all" /}
<tr><td colspan="2"><hr>
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'WHOIS server' /}
{param name: 'whoisServer' /}
{param value: $whoisServerNonNull /}
{param readonly: $readonly /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Referral URL' /}
{param name: 'url' /}
{param value: $urlNonNull /}
{param readonly: $readonly /}
{/call}
</table>
</form>
{/template}
/**
* Contact info.
*/
{template .contactInfo_ visibility="private"}
{@param? emailAddress: string}
{@param readonly: bool}
{@param? localizedAddress: ?}
{@param? phoneNumber: string}
{@param? faxNumber: string}
{if $readonly}
<tr class="{css('kd-settings-pane-section')}">
<td><label class="{css('setting-label')}">Contact info</label></td>
<td class="{css('setting-group-compact')}">
{if isNonnull($localizedAddress)}
{call .viewAddress_ data="$localizedAddress"}
{param id: 'localizedAddress' /}
{/call}
{/if}
{if isNonnull($phoneNumber)}
<input type="hidden"
name="phoneNumber"
id="phoneNumber"
value="{$phoneNumber}">
<div class="{css('contact-phone-number')}">{$phoneNumber}</div>
{/if}
{if isNonnull($faxNumber)}
<input type="hidden"
name="faxNumber"
id="faxNumber"
value="{$faxNumber}">
<div class="{css('contact-fax-number')}">{$faxNumber} (Fax)</div>
{/if}
{if isNonnull($emailAddress)}
<input type="hidden"
name="emailAddress"
id="emailAddress"
value="{$emailAddress}">
<div class="{css('contact-fax-number')}">{$emailAddress}</div>
{/if}
</td>
{else}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Email' /}
{param name: 'emailAddress' /}
{param value: $emailAddress /}
{param readonly: false /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Phone' /}
{param name: 'phoneNumber' /}
{param value: $phoneNumber /}
{param readonly: false /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Fax' /}
{param name: 'faxNumber' /}
{param value: $faxNumber /}
{param readonly: false /}
{/call}
{call .editAddress_ data="$localizedAddress"}
{param id: 'localizedAddress' /}
{/call}
{/if}
{/template}
/**
* Read-only view of address.
*/
{template .viewAddress_ visibility="private"}
{@param id: string}
{@param street: list<string>}
{@param city: string}
{@param? state: string}
{@param? zip: string}
{@param countryCode: string}
{for $line in $street}
<input type="hidden"
name="{$id}.street[{index($line)}]"
id="{$id}.street[{index($line)}]"
value="{$street[index($line)]}">
<div class="{css('contact-address-street')}">{$street[index($line)]}</div>
{/for}
<input type="hidden" name="{$id}.city" id="{$id}.city" value="{$city}">
<input type="hidden" name="{$id}.state" id="{$id}.state" value="{$state}">
<input type="hidden" name="{$id}.zip" id="{$id}.zip" value="{$zip}">
<input type="hidden"
name="{$id}.countryCode"
id="{$id}.countryCode"
value="{$countryCode}">
<div class="{css('contact-address-city')}">{$city},</div>
{if isNonnull($state)}
{sp}<div class="{css('contact-address-state')}">{$state}</div>
{/if}
{if isNonnull($zip)}
{sp}<div class="{css('contact-address-zip')}">{$zip}</div>
{/if}
{sp}<div class="{css('contact-address-cc')}">{$countryCode}</div>
{/template}
/**
* Editor of address.
*/
{template .editAddress_ visibility="private"}
{@param id: string}
{@param? street: list<string>}
{@param? city: string}
{@param? state: string}
{@param? zip: string}
{@param? countryCode: string}
{let $street2: $street ?: [] /}
{let $city2: $city ?: '' /}
{let $state2: $state ?: '' /}
{let $zip2: $zip ?: '' /}
{let $countryCode2: $countryCode ?: '' /}
<tr class="{css('kd-settings-pane-section')}">
<td>
<label for="{$id}.street[0]"
class="{css('setting-label')}">Street Address</label>
<td class="{css('setting')}">
<input id="{$id}.street[0]"
name="{$id}.street[0]"
value="{if isNonnull($street2[0])}{$street2[0]}{/if}">
<input id="{$id}.street[1]"
name="{$id}.street[1]"
value="{if isNonnull($street2[1])}{$street2[1]}{/if}">
<input id="{$id}.street[2]"
name="{$id}.street[2]"
value="{if isNonnull($street2[2])}{$street2[2]}{/if}">
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'City' /}
{param name: $id + '.city' /}
{param value: $city2 /}
{param readonly: false /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'State/Region' /}
{param name: $id + '.state' /}
{param value: $state2 /}
{param readonly: false /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Zip/Postal Code' /}
{param name: $id + '.zip' /}
{param value: $zip2 /}
{param readonly: false /}
{/call}
{call registry.soy.forms.inputFieldRowWithValue}
{param label: 'Country Code' /}
{param name: $id + '.countryCode' /}
{param value: $countryCode2 /}
{param readonly: false /}
{/call}
{/template}

21
package-lock.json generated
View File

@@ -1,21 +0,0 @@
{
"name": "nomulus",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "nomulus",
"version": "1.0.0",
"license": "Apache-2.0",
"dependencies": {
"google-closure-library": "20210406.0.0"
}
},
"node_modules/google-closure-library": {
"version": "20210406.0.0",
"resolved": "https://registry.npmjs.org/google-closure-library/-/google-closure-library-20210406.0.0.tgz",
"integrity": "sha512-1lAC/KC9R2QM6nygniM0pRcGrv5bkCUrIZb2hXFxLtAkA+zRiVeWtRYpFWDHXXJzkavKjsn9upiffL4x/nmmVg=="
}
}
}

View File

@@ -1,22 +0,0 @@
{
"name": "nomulus",
"version": "1.0.0",
"description": "Top-level domain name registry service on Google App Engine https://registry.google",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/google/nomulus.git"
},
"author": "",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/google/nomulus/issues"
},
"homepage": "https://github.com/google/nomulus#readme",
"dependencies": {
"google-closure-library": "20210406.0.0"
}
}