1
0
mirror of https://github.com/google/nomulus synced 2026-01-03 03:35:42 +00:00

Disable primary-contact editing in console (#2745)

This is necessary because we'll use primary-contact emails as a way of
resetting passwords.

In the UI, don't allow editing of email address for primary contacts,
and don't allow addition/removal of the primary contact field
post-creation.

In the backend, make sure that all emails previously added still exist.
This commit is contained in:
gbrodman
2025-04-29 13:32:29 -04:00
committed by GitHub
parent 56cd2ad282
commit daa7ab3bfa
8 changed files with 147 additions and 117 deletions

View File

@@ -16,11 +16,7 @@ import { Component, effect, ViewEncapsulation } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { take } from 'rxjs'; import { take } from 'rxjs';
import { RegistrarService } from 'src/app/registrar/registrar.service'; import { RegistrarService } from 'src/app/registrar/registrar.service';
import { import { ContactService, ViewReadyContact } from './contact.service';
ContactService,
contactTypeToViewReadyContact,
ViewReadyContact,
} from './contact.service';
@Component({ @Component({
selector: 'app-contact', selector: 'app-contact',

View File

@@ -83,7 +83,7 @@ export class ContactService {
: contactTypeToViewReadyContact({ : contactTypeToViewReadyContact({
emailAddress: '', emailAddress: '',
name: '', name: '',
types: ['ADMIN'], types: ['TECH'],
faxNumber: '', faxNumber: '',
phoneNumber: '', phoneNumber: '',
registrarId: '', registrarId: '',

View File

@@ -56,6 +56,7 @@
[required]="true" [required]="true"
[(ngModel)]="contactService.contactInEdit.emailAddress" [(ngModel)]="contactService.contactInEdit.emailAddress"
[ngModelOptions]="{ standalone: true }" [ngModelOptions]="{ standalone: true }"
[disabled]="emailAddressIsDisabled()"
/> />
</mat-form-field> </mat-form-field>
@@ -85,14 +86,18 @@
<mat-icon color="accent">error</mat-icon>Required to select at least one <mat-icon color="accent">error</mat-icon>Required to select at least one
</p> </p>
<div class=""> <div class="">
<mat-checkbox <ng-container
*ngFor="let contactType of contactTypeToTextMap | keyvalue" *ngFor="let contactType of contactTypeToTextMap | keyvalue"
[checked]="checkboxIsChecked(contactType.key)"
(change)="checkboxOnChange($event, contactType.key)"
[disabled]="checkboxIsDisabled(contactType.key)"
> >
{{ contactType.value }} <mat-checkbox
</mat-checkbox> *ngIf="shouldDisplayCheckbox(contactType.key)"
[checked]="checkboxIsChecked(contactType.key)"
(change)="checkboxOnChange($event, contactType.key)"
[disabled]="checkboxIsDisabled(contactType.key)"
>
{{ contactType.value }}
</mat-checkbox>
</ng-container>
</div> </div>
</section> </section>

View File

@@ -82,6 +82,10 @@ export class ContactDetailsComponent {
}); });
} }
shouldDisplayCheckbox(type: string) {
return type !== 'ADMIN' || this.checkboxIsChecked(type);
}
checkboxIsChecked(type: string) { checkboxIsChecked(type: string) {
return this.contactService.contactInEdit.types.includes( return this.contactService.contactInEdit.types.includes(
type as contactType type as contactType
@@ -89,6 +93,9 @@ export class ContactDetailsComponent {
} }
checkboxIsDisabled(type: string) { checkboxIsDisabled(type: string) {
if (type === 'ADMIN') {
return true;
}
return ( return (
this.contactService.contactInEdit.types.length === 1 && this.contactService.contactInEdit.types.length === 1 &&
this.contactService.contactInEdit.types[0] === (type as contactType) this.contactService.contactInEdit.types[0] === (type as contactType)
@@ -105,4 +112,8 @@ export class ContactDetailsComponent {
); );
} }
} }
emailAddressIsDisabled() {
return this.contactService.contactInEdit.types.includes('ADMIN');
}
} }

View File

@@ -169,6 +169,7 @@ public class ContactAction extends ConsoleApiAction {
throw new ContactRequirementException(t); throw new ContactRequirementException(t);
} }
} }
enforcePrimaryContactRestrictions(oldContactsByType, newContactsByType);
ensurePhoneNumberNotRemovedForContactTypes(oldContactsByType, newContactsByType, Type.TECH); ensurePhoneNumberNotRemovedForContactTypes(oldContactsByType, newContactsByType, Type.TECH);
Optional<RegistrarPoc> domainWhoisAbuseContact = Optional<RegistrarPoc> domainWhoisAbuseContact =
getDomainWhoisVisibleAbuseContact(updatedContacts); getDomainWhoisVisibleAbuseContact(updatedContacts);
@@ -187,6 +188,23 @@ public class ContactAction extends ConsoleApiAction {
checkContactRegistryLockRequirements(existingContacts, updatedContacts); checkContactRegistryLockRequirements(existingContacts, updatedContacts);
} }
private static void enforcePrimaryContactRestrictions(
Multimap<Type, RegistrarPoc> oldContactsByType,
Multimap<Type, RegistrarPoc> newContactsByType) {
ImmutableSet<String> oldAdminEmails =
oldContactsByType.get(Type.ADMIN).stream()
.map(RegistrarPoc::getEmailAddress)
.collect(toImmutableSet());
ImmutableSet<String> newAdminEmails =
newContactsByType.get(Type.ADMIN).stream()
.map(RegistrarPoc::getEmailAddress)
.collect(toImmutableSet());
if (!newAdminEmails.containsAll(oldAdminEmails)) {
throw new ContactRequirementException(
"Cannot remove or change the email address of primary contacts");
}
}
private static void checkContactRegistryLockRequirements( private static void checkContactRegistryLockRequirements(
ImmutableSet<RegistrarPoc> existingContacts, ImmutableSet<RegistrarPoc> updatedContacts) { ImmutableSet<RegistrarPoc> existingContacts, ImmutableSet<RegistrarPoc> updatedContacts) {
// Any contact(s) with new passwords must be allowed to set them // Any contact(s) with new passwords must be allowed to set them

View File

@@ -18,6 +18,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE; import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN; import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.MARKETING;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH; import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
import static google.registry.testing.DatabaseHelper.createAdminUser; import static google.registry.testing.DatabaseHelper.createAdminUser;
import static google.registry.testing.DatabaseHelper.insertInDb; import static google.registry.testing.DatabaseHelper.insertInDb;
@@ -70,8 +71,9 @@ class ContactActionTest {
private Registrar testRegistrar; private Registrar testRegistrar;
private ConsoleApiParams consoleApiParams; private ConsoleApiParams consoleApiParams;
private RegistrarPoc testRegistrarPoc1; private RegistrarPoc adminPoc;
private RegistrarPoc testRegistrarPoc2; private RegistrarPoc techPoc;
private RegistrarPoc marketingPoc;
private static final Gson GSON = RequestModule.provideGson(); private static final Gson GSON = RequestModule.provideGson();
@@ -82,7 +84,7 @@ class ContactActionTest {
@BeforeEach @BeforeEach
void beforeEach() { void beforeEach() {
testRegistrar = saveRegistrar("registrarId"); testRegistrar = saveRegistrar("registrarId");
testRegistrarPoc1 = adminPoc =
new RegistrarPoc.Builder() new RegistrarPoc.Builder()
.setRegistrar(testRegistrar) .setRegistrar(testRegistrar)
.setName("Test Registrar 1") .setName("Test Registrar 1")
@@ -94,19 +96,32 @@ class ContactActionTest {
.setVisibleInWhoisAsTech(false) .setVisibleInWhoisAsTech(false)
.setVisibleInDomainWhoisAsAbuse(false) .setVisibleInDomainWhoisAsAbuse(false)
.build(); .build();
testRegistrarPoc2 = techPoc =
testRegistrarPoc1 adminPoc
.asBuilder() .asBuilder()
.setName("Test Registrar 2") .setName("Test Registrar 2")
.setTypes(ImmutableSet.of(TECH))
.setVisibleInWhoisAsTech(true)
.setVisibleInWhoisAsAdmin(false)
.setEmailAddress("test.registrar2@example.com") .setEmailAddress("test.registrar2@example.com")
.setPhoneNumber("+1.1234567890") .setPhoneNumber("+1.1234567890")
.setFaxNumber("+1.1234567891") .setFaxNumber("+1.1234567891")
.build(); .build();
marketingPoc =
adminPoc
.asBuilder()
.setName("Test Registrar 3")
.setTypes(ImmutableSet.of(MARKETING))
.setVisibleInWhoisAsAdmin(false)
.setEmailAddress("test.registrar3@example.com")
.setPhoneNumber("+1.1238675309")
.setFaxNumber("+1.1238675309")
.build();
} }
@Test @Test
void testSuccess_getContactInfo() throws IOException { void testSuccess_getContactInfo() throws IOException {
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.GET, Action.Method.GET,
@@ -120,13 +135,13 @@ class ContactActionTest {
@Test @Test
void testSuccess_noOp() throws IOException { void testSuccess_noOp() throws IOException {
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1); adminPoc);
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
verify(consoleApiParams.sendEmailUtils().gmailClient, never()).sendEmail(any()); verify(consoleApiParams.sendEmailUtils().gmailClient, never()).sendEmail(any());
@@ -134,8 +149,8 @@ class ContactActionTest {
@Test @Test
void testSuccess_onlyContactsWithNonEmptyType() throws IOException { void testSuccess_onlyContactsWithNonEmptyType() throws IOException {
testRegistrarPoc1 = testRegistrarPoc1.asBuilder().setTypes(ImmutableSet.of()).build(); adminPoc = adminPoc.asBuilder().setTypes(ImmutableSet.of()).build();
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.GET, Action.Method.GET,
@@ -148,14 +163,14 @@ class ContactActionTest {
@Test @Test
void testSuccess_postCreateContactInfo() throws IOException { void testSuccess_postCreateContactInfo() throws IOException {
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1, adminPoc,
testRegistrarPoc2); techPoc);
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat( assertThat(
@@ -168,14 +183,14 @@ class ContactActionTest {
@Test @Test
void testSuccess_postUpdateContactInfo() throws IOException { void testSuccess_postUpdateContactInfo() throws IOException {
insertInDb(testRegistrarPoc1.asBuilder().setEmailAddress("incorrect@email.com").build()); insertInDb(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1, adminPoc,
testRegistrarPoc2); techPoc);
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
HashMap<String, String> testResult = new HashMap<>(); HashMap<String, String> testResult = new HashMap<>();
@@ -197,8 +212,8 @@ class ContactActionTest {
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1, adminPoc,
testRegistrarPoc2.asBuilder().setEmailAddress("test.registrar1@example.com").build()); techPoc.asBuilder().setEmailAddress("test.registrar1@example.com").build());
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload()) assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
@@ -213,13 +228,13 @@ class ContactActionTest {
@Test @Test
void testFailure_postUpdateContactInfo_requiredContactRemoved() throws IOException { void testFailure_postUpdateContactInfo_requiredContactRemoved() throws IOException {
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1.asBuilder().setTypes(ImmutableSet.of(ABUSE)).build()); adminPoc.asBuilder().setTypes(ImmutableSet.of(ABUSE)).build());
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload()) assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
@@ -228,20 +243,19 @@ class ContactActionTest {
loadAllOf(RegistrarPoc.class).stream() loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId())) .filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList())) .collect(toImmutableList()))
.containsExactly(testRegistrarPoc1); .containsExactly(adminPoc);
} }
@Test @Test
void testFailure_postUpdateContactInfo_phoneNumberRemoved() throws IOException { void testFailure_postUpdateContactInfo_phoneNumberRemoved() throws IOException {
testRegistrarPoc1 = adminPoc = adminPoc.asBuilder().setTypes(ImmutableSet.of(ADMIN, TECH)).build();
testRegistrarPoc1.asBuilder().setTypes(ImmutableSet.of(ADMIN, TECH)).build(); insertInDb(adminPoc);
insertInDb(testRegistrarPoc1);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1 adminPoc
.asBuilder() .asBuilder()
.setPhoneNumber(null) .setPhoneNumber(null)
.setTypes(ImmutableSet.of(ADMIN, TECH)) .setTypes(ImmutableSet.of(ADMIN, TECH))
@@ -254,7 +268,7 @@ class ContactActionTest {
loadAllOf(RegistrarPoc.class).stream() loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId())) .filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList())) .collect(toImmutableList()))
.containsExactly(testRegistrarPoc1); .containsExactly(adminPoc);
} }
@Test @Test
@@ -264,11 +278,7 @@ class ContactActionTest {
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1 adminPoc.asBuilder().setPhoneNumber(null).setVisibleInDomainWhoisAsAbuse(true).build());
.asBuilder()
.setPhoneNumber(null)
.setVisibleInDomainWhoisAsAbuse(true)
.build());
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload()) assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
@@ -282,14 +292,14 @@ class ContactActionTest {
@Test @Test
void testFailure_postUpdateContactInfo_whoisContactPhoneNumberRemoved() throws IOException { void testFailure_postUpdateContactInfo_whoisContactPhoneNumberRemoved() throws IOException {
testRegistrarPoc1 = testRegistrarPoc1.asBuilder().setVisibleInDomainWhoisAsAbuse(true).build(); adminPoc = adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(true).build();
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1.asBuilder().setVisibleInDomainWhoisAsAbuse(false).build()); adminPoc.asBuilder().setVisibleInDomainWhoisAsAbuse(false).build());
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload()) assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
@@ -298,7 +308,7 @@ class ContactActionTest {
loadAllOf(RegistrarPoc.class).stream() loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId())) .filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList())) .collect(toImmutableList()))
.containsExactly(testRegistrarPoc1); .containsExactly(adminPoc);
} }
@Test @Test
@@ -309,7 +319,7 @@ class ContactActionTest {
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1 adminPoc
.asBuilder() .asBuilder()
.setAllowedToSetRegistryLockPassword(true) .setAllowedToSetRegistryLockPassword(true)
.setRegistryLockEmailAddress("lock@example.com") .setRegistryLockEmailAddress("lock@example.com")
@@ -327,22 +337,19 @@ class ContactActionTest {
@Test @Test
void testFailure_postUpdateContactInfo_cannotModifyRegistryLockEmail() throws IOException { void testFailure_postUpdateContactInfo_cannotModifyRegistryLockEmail() throws IOException {
testRegistrarPoc1 = adminPoc =
testRegistrarPoc1 adminPoc
.asBuilder() .asBuilder()
.setRegistryLockEmailAddress("lock@example.com") .setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(true) .setAllowedToSetRegistryLockPassword(true)
.build(); .build();
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1 adminPoc.asBuilder().setRegistryLockEmailAddress("unlock@example.com").build());
.asBuilder()
.setRegistryLockEmailAddress("unlock@example.com")
.build());
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload()) assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
@@ -351,25 +358,25 @@ class ContactActionTest {
loadAllOf(RegistrarPoc.class).stream() loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId())) .filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList())) .collect(toImmutableList()))
.containsExactly(testRegistrarPoc1); .containsExactly(adminPoc);
} }
@Test @Test
void testFailure_postUpdateContactInfo_cannotSetIsAllowedToSetRegistryLockPassword() void testFailure_postUpdateContactInfo_cannotSetIsAllowedToSetRegistryLockPassword()
throws IOException { throws IOException {
testRegistrarPoc1 = adminPoc =
testRegistrarPoc1 adminPoc
.asBuilder() .asBuilder()
.setRegistryLockEmailAddress("lock@example.com") .setRegistryLockEmailAddress("lock@example.com")
.setAllowedToSetRegistryLockPassword(false) .setAllowedToSetRegistryLockPassword(false)
.build(); .build();
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1.asBuilder().setAllowedToSetRegistryLockPassword(true).build()); adminPoc.asBuilder().setAllowedToSetRegistryLockPassword(true).build());
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
assertThat(((FakeResponse) consoleApiParams.response()).getPayload()) assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
@@ -378,18 +385,18 @@ class ContactActionTest {
loadAllOf(RegistrarPoc.class).stream() loadAllOf(RegistrarPoc.class).stream()
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId())) .filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.collect(toImmutableList())) .collect(toImmutableList()))
.containsExactly(testRegistrarPoc1); .containsExactly(adminPoc);
} }
@Test @Test
void testSuccess_sendsEmail() throws IOException, AddressException { void testSuccess_sendsEmail() throws IOException, AddressException {
insertInDb(testRegistrarPoc1.asBuilder().setEmailAddress("incorrect@email.com").build()); insertInDb(techPoc.asBuilder().setEmailAddress("incorrect@email.com").build());
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc1); techPoc);
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
verify(consoleApiParams.sendEmailUtils().gmailClient, times(1)) verify(consoleApiParams.sendEmailUtils().gmailClient, times(1))
@@ -404,44 +411,42 @@ class ContactActionTest {
+ "\n" + "\n"
+ "contacts:\n" + "contacts:\n"
+ " ADDED:\n" + " ADDED:\n"
+ " {name=Test Registrar 1," + " {name=Test Registrar 2,"
+ " emailAddress=test.registrar1@example.com, registrarId=registrarId," + " emailAddress=test.registrar2@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.9999999999," + " registryLockEmailAddress=null, phoneNumber=+1.1234567890,"
+ " faxNumber=+1.9999999991, types=[ADMIN]," + " faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false," + " visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=true,"
+ " visibleInDomainWhoisAsAbuse=false," + " visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n" + " allowedToSetRegistryLockPassword=false}\n"
+ " REMOVED:\n" + " REMOVED:\n"
+ " {name=Test Registrar 1, emailAddress=incorrect@email.com," + " {name=Test Registrar 2, emailAddress=incorrect@email.com,"
+ " registrarId=registrarId, registryLockEmailAddress=null," + " registrarId=registrarId, registryLockEmailAddress=null,"
+ " phoneNumber=+1.9999999999, faxNumber=+1.9999999991, types=[ADMIN]," + " phoneNumber=+1.1234567890, faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=true," + " visibleInWhoisAsAdmin=false,"
+ " visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false," + " visibleInWhoisAsTech=true, visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n" + " allowedToSetRegistryLockPassword=false}\n"
+ " FINAL CONTENTS:\n" + " FINAL CONTENTS:\n"
+ " {name=Test Registrar 1," + " {name=Test Registrar 2,"
+ " emailAddress=test.registrar1@example.com, registrarId=registrarId," + " emailAddress=test.registrar2@example.com, registrarId=registrarId,"
+ " registryLockEmailAddress=null, phoneNumber=+1.9999999999," + " registryLockEmailAddress=null, phoneNumber=+1.1234567890,"
+ " faxNumber=+1.9999999991, types=[ADMIN]," + " faxNumber=+1.1234567891, types=[TECH],"
+ " visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false," + " visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=true,"
+ " visibleInDomainWhoisAsAbuse=false," + " visibleInDomainWhoisAsAbuse=false,"
+ " allowedToSetRegistryLockPassword=false}\n") + " allowedToSetRegistryLockPassword=false}\n")
.setRecipients( .setRecipients(ImmutableList.of(new InternetAddress("notification@test.example")))
ImmutableList.of(
new InternetAddress("notification@test.example"),
new InternetAddress("incorrect@email.com")))
.build()); .build());
} }
@Test @Test
void testSuccess_postDeleteContactInfo() throws IOException { void testSuccess_postDeleteContactInfo() throws IOException {
insertInDb(testRegistrarPoc1); insertInDb(adminPoc, techPoc, marketingPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")), AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc2); adminPoc,
techPoc);
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertThat( assertThat(
@@ -449,12 +454,12 @@ class ContactActionTest {
.filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId())) .filter(r -> r.registrarId.equals(testRegistrar.getRegistrarId()))
.map(r -> r.getName()) .map(r -> r.getName())
.collect(toImmutableList())) .collect(toImmutableList()))
.containsExactly("Test Registrar 2"); .containsExactly("Test Registrar 1", "Test Registrar 2");
} }
@Test @Test
void testFailure_postDeleteContactInfo_missingPermission() throws IOException { void testFailure_postDeleteContactInfo_missingPermission() throws IOException {
insertInDb(testRegistrarPoc1); insertInDb(adminPoc);
ContactAction action = ContactAction action =
createAction( createAction(
Action.Method.POST, Action.Method.POST,
@@ -469,11 +474,27 @@ class ContactActionTest {
.build()) .build())
.build()), .build()),
testRegistrar.getRegistrarId(), testRegistrar.getRegistrarId(),
testRegistrarPoc2); techPoc);
action.run(); action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
} }
@Test
void testFailure_changesAdminEmail() throws Exception {
insertInDb(adminPoc.asBuilder().setEmailAddress("oldemail@example.com").build());
ContactAction action =
createAction(
Action.Method.POST,
AuthResult.createUser(createAdminUser("email@email.com")),
testRegistrar.getRegistrarId(),
adminPoc);
action.run();
FakeResponse fakeResponse = (FakeResponse) consoleApiParams.response();
assertThat(fakeResponse.getStatus()).isEqualTo(400);
assertThat(fakeResponse.getPayload())
.isEqualTo("Cannot remove or change the email address of primary contacts");
}
private ContactAction createAction( private ContactAction createAction(
Action.Method method, AuthResult authResult, String registrarId, RegistrarPoc... contacts) Action.Method method, AuthResult authResult, String registrarId, RegistrarPoc... contacts)
throws IOException { throws IOException {

View File

@@ -23,6 +23,7 @@ import google.registry.model.console.RegistrarRole;
import google.registry.server.RegistryTestServer; import google.registry.server.RegistryTestServer;
import java.util.List; import java.util.List;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junitpioneer.jupiter.RetryingTest; import org.junitpioneer.jupiter.RetryingTest;
@@ -50,7 +51,15 @@ import org.openqa.selenium.WebElement;
*/ */
// The Selenium image only supports amd64 architecture. // The Selenium image only supports amd64 architecture.
@EnabledIfSystemProperty(named = "os.arch", matches = "amd64") @EnabledIfSystemProperty(named = "os.arch", matches = "amd64")
public class ConsoleScreenshotTest extends WebDriverTestCase { @Timeout(120)
public class ConsoleScreenshotTest {
@RegisterExtension
static final DockerWebDriverExtension webDriverProvider = new DockerWebDriverExtension();
@RegisterExtension
final WebDriverPlusScreenDifferExtension driver =
new WebDriverPlusScreenDifferExtension(webDriverProvider::getWebDriver);
@RegisterExtension @RegisterExtension
final TestServerExtension server = final TestServerExtension server =

View File

@@ -1,30 +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.
package google.registry.webdriver;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Base class for tests that needs a {@link WebDriverPlusScreenDifferExtension}. */
@Timeout(120)
class WebDriverTestCase {
@RegisterExtension
static final DockerWebDriverExtension webDriverProvider = new DockerWebDriverExtension();
@RegisterExtension
final WebDriverPlusScreenDifferExtension driver =
new WebDriverPlusScreenDifferExtension(webDriverProvider::getWebDriver);
}