diff --git a/java/google/registry/model/domain/LrpToken.java b/java/google/registry/model/domain/LrpToken.java new file mode 100644 index 000000000..5f8a7141f --- /dev/null +++ b/java/google/registry/model/domain/LrpToken.java @@ -0,0 +1,96 @@ +// Copyright 2016 The Domain Registry 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. + +package google.registry.model.domain; + +import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; + +import com.googlecode.objectify.Key; +import com.googlecode.objectify.annotation.Entity; +import com.googlecode.objectify.annotation.Id; +import com.googlecode.objectify.annotation.Index; +import google.registry.model.BackupGroupRoot; +import google.registry.model.Buildable; +import google.registry.model.reporting.HistoryEntry; +import google.registry.model.reporting.HistoryEntry.Type; + +/** + * An entity representing a token distributed to eligible LRP registrants. + */ +@Entity +public class LrpToken extends BackupGroupRoot implements Buildable { + + /** + * The token's assignee (a unique identifier). + */ + @Id + String assignee; + + /** + * The secret token assigned to a registrant for the purposes of LRP registration. + */ + @Index + String token; + + /** + * The key of the history entry for which the token was used. Given LRP is a domain application + * phase, this should always be a {@link Type#DOMAIN_APPLICATION_CREATE}. + */ + Key redemptionHistoryEntry; + + public String getToken() { + return token; + } + + public String getAssignee() { + return assignee; + } + + public Key getRedemptionHistoryEntry() { + return redemptionHistoryEntry; + } + + public boolean isRedeemed() { + return redemptionHistoryEntry != null; + } + + @Override + public Builder asBuilder() { + return new Builder(clone(this)); + } + + /** A builder for constructing {@link LrpToken} objects, since they are immutable. */ + public static class Builder extends Buildable.Builder { + public Builder() {} + + private Builder(LrpToken instance) { + super(instance); + } + + public Builder setAssignee(String assignee) { + getInstance().assignee = assignee; + return this; + } + + public Builder setToken(String token) { + getInstance().token = checkArgumentNotNull(token); + return this; + } + + public Builder setRedemptionHistoryEntry(Key redemptionHistoryEntry) { + getInstance().redemptionHistoryEntry = checkArgumentNotNull(redemptionHistoryEntry); + return this; + } + } +} diff --git a/java/google/registry/tools/GetLrpTokenCommand.java b/java/google/registry/tools/GetLrpTokenCommand.java new file mode 100644 index 000000000..2c8ef1177 --- /dev/null +++ b/java/google/registry/tools/GetLrpTokenCommand.java @@ -0,0 +1,75 @@ +// Copyright 2016 The Domain Registry 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. + +package google.registry.tools; + +import static com.google.common.base.Preconditions.checkArgument; +import static google.registry.model.ofy.ObjectifyService.ofy; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import com.googlecode.objectify.Key; +import google.registry.model.domain.LrpToken; +import google.registry.tools.Command.GtechCommand; +import google.registry.tools.Command.RemoteApiCommand; + +/** Command to show token information for LRP participants. */ +@Parameters( + separators = " =", + commandDescription = "Show token information for LRP participants by matching on a " + + "known token or a unique ID (assignee).") +public final class GetLrpTokenCommand implements RemoteApiCommand, GtechCommand { + + @Parameter( + names = {"-t", "--token"}, + description = "LRP access token (auth code) to check") + private String tokenString; + + @Parameter( + names = {"-a", "--assignee"}, + description = "LRP token assignee") + private String assignee; + + @Parameter( + names = {"-h", "--history"}, + description = "Return expanded history entry (including domain application)") + private boolean includeHistory = false; + + @Override + public void run() throws Exception { + checkArgument( + (tokenString == null) == (assignee != null), + "Exactly one of either token or assignee must be specified."); + LrpToken token = null; + if (assignee != null) { + token = ofy().load().key(Key.create(LrpToken.class, assignee)).now(); + } else if (tokenString != null) { + token = ofy().load() + .type(LrpToken.class) + .filter("token", tokenString) + .first() + .now(); + } + if (token != null) { + System.out.println(token); + if (includeHistory && token.getRedemptionHistoryEntry() != null) { + System.out.println( + ofy().load().key(token.getRedemptionHistoryEntry()).now().toHydratedString()); + } + } else { + System.out.println("Token not found."); + } + } +} + diff --git a/java/google/registry/tools/GtechTool.java b/java/google/registry/tools/GtechTool.java index 2736576c3..055d32e6d 100644 --- a/java/google/registry/tools/GtechTool.java +++ b/java/google/registry/tools/GtechTool.java @@ -52,6 +52,7 @@ public final class GtechTool { .put("get_applied_labels", GetAppliedLabelsCommand.class) .put("get_contact", GetContactCommand.class) .put("get_domain", GetDomainCommand.class) + .put("get_lrp_token", GetLrpTokenCommand.class) .put("get_history_entries", GetHistoryEntriesCommand.class) .put("get_host", GetHostCommand.class) .put("get_registrar", GetRegistrarCommand.class) diff --git a/javatests/google/registry/tools/GetLrpTokenCommandTest.java b/javatests/google/registry/tools/GetLrpTokenCommandTest.java new file mode 100644 index 000000000..70ffb4fd7 --- /dev/null +++ b/javatests/google/registry/tools/GetLrpTokenCommandTest.java @@ -0,0 +1,88 @@ +// Copyright 2016 The Domain Registry 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. + +package google.registry.tools; + +import static google.registry.testing.DatastoreHelper.createTld; +import static google.registry.testing.DatastoreHelper.persistActiveDomainApplication; +import static google.registry.testing.DatastoreHelper.persistResource; + +import com.googlecode.objectify.Key; +import google.registry.model.domain.DomainApplication; +import google.registry.model.domain.LrpToken; +import google.registry.model.reporting.HistoryEntry; +import org.junit.Before; +import org.junit.Test; + +/** Unit tests for {@link GetLrpTokenCommand}. */ +public class GetLrpTokenCommandTest + extends CommandTestCase { + + @Before + public void before() { + createTld("tld"); + DomainApplication lrpApplication = persistActiveDomainApplication("domain.tld"); + HistoryEntry applicationCreateHistoryEntry = persistResource(new HistoryEntry.Builder() + .setParent(lrpApplication) + .setType(HistoryEntry.Type.DOMAIN_APPLICATION_CREATE) + .build()); + persistResource( + new LrpToken.Builder() + .setAssignee("domain.tld") + .setToken("domain_token") + .setRedemptionHistoryEntry(Key.create(applicationCreateHistoryEntry)) + .build()); + } + + @Test + public void testSuccess_byAssignee() throws Exception { + runCommand("--assignee=domain.tld"); + assertInStdout("domain_token"); + } + + @Test + public void testSuccess_byToken() throws Exception { + runCommand("--token=domain_token"); + assertInStdout("domain.tld"); + assertNotInStdout("fullyQualifiedDomainName=domain.tld"); // history param should be false + } + + @Test + public void testSuccess_iosByToken_withHistory() throws Exception { + runCommand("--token=domain_token", "--history"); + assertInStdout("domain.tld"); + assertInStdout("fullyQualifiedDomainName=domain.tld"); + assertInStdout("type=DOMAIN_APPLICATION_CREATE"); + } + + @Test + public void testSuccess_unknownAssignee() throws Exception { + runCommand("--assignee=nobody"); + assertInStdout("Token not found"); + } + + @Test + public void testSuccess_unknownToken() throws Exception { + runCommand("--token=bogus_token"); + assertInStdout("Token not found"); + } + + @Test + public void testFailure_noArgs() throws Exception { + thrown.expect( + IllegalArgumentException.class, + "Exactly one of either token or assignee must be specified."); + runCommand(); + } +}