mirror of
https://github.com/google/nomulus
synced 2026-05-26 17:50:33 +00:00
Compare commits
7 Commits
proxy-2024
...
proxy-2024
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa377733be | ||
|
|
21950f7d82 | ||
|
|
e66aee0416 | ||
|
|
c7e1fc17d2 | ||
|
|
0c0b0df36e | ||
|
|
304f0002b4 | ||
|
|
15cf3e1bc0 |
@@ -166,9 +166,9 @@ export class BackendService {
|
||||
.pipe(catchError((err) => this.errorCatcher<User[]>(err)));
|
||||
}
|
||||
|
||||
createUser(registrarId: string): Observable<User> {
|
||||
createUser(registrarId: string, maybeUser: User | null): Observable<User> {
|
||||
return this.http
|
||||
.post<User>(`/console-api/users?registrarId=${registrarId}`, {})
|
||||
.post<User>(`/console-api/users?registrarId=${registrarId}`, maybeUser)
|
||||
.pipe(catchError((err) => this.errorCatcher<User>(err)));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface UserData {
|
||||
supportEmail: string;
|
||||
supportPhoneNumber: string;
|
||||
technicalDocsUrl: string;
|
||||
userRoles?: Map<string, string>;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
|
||||
@@ -19,7 +19,7 @@ import { SelectedRegistrarModule } from '../app.module';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { RegistrarService } from '../registrar/registrar.service';
|
||||
import { SnackBarModule } from '../snackbar.module';
|
||||
import { User, UsersService, roleToDescription } from './users.service';
|
||||
import { UsersService, roleToDescription } from './users.service';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -3,6 +3,62 @@
|
||||
<div class="console-app__users-spinner">
|
||||
<mat-spinner />
|
||||
</div>
|
||||
} @else if(selectingExistingUser) {
|
||||
|
||||
<div class="console-app__users">
|
||||
<h1 class="mat-headline-4">Add existing user</h1>
|
||||
|
||||
<p>
|
||||
<button
|
||||
mat-icon-button
|
||||
aria-label="Back to users list"
|
||||
(click)="selectingExistingUser = false"
|
||||
>
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</button>
|
||||
</p>
|
||||
<h1>Select registrar from which to add a new user</h1>
|
||||
<p>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Registrar</mat-label>
|
||||
<mat-select
|
||||
[(ngModel)]="selectedRegistrarId"
|
||||
name="selectedRegistrarId"
|
||||
(selectionChange)="onRegistrarSelectionChange($event)"
|
||||
>
|
||||
@for (registrar of registrarService.registrars(); track registrar) {
|
||||
<mat-option [value]="registrar.registrarId">{{
|
||||
registrar.registrarId
|
||||
}}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
@if(usersSelection.length) {
|
||||
<app-users-list
|
||||
[users]="usersSelection"
|
||||
(onSelect)="existingUserSelected($event)"
|
||||
/>
|
||||
<p class="console-app__users-add-existing">
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
aria-label="Add user"
|
||||
(click)="submitExistingUser()"
|
||||
[disabled]="!selectedExistingUser"
|
||||
>
|
||||
Add user
|
||||
</button>
|
||||
<button
|
||||
mat-stroked-button
|
||||
aria-label="Cancel adding existing user"
|
||||
(click)="selectingExistingUser = false"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
} @else if(usersService.currentlyOpenUserEmail()) {
|
||||
<app-user-edit></app-user-edit>
|
||||
} @else {
|
||||
@@ -10,39 +66,31 @@
|
||||
<div class="console-app__users-header">
|
||||
<h1 class="mat-headline-4">Users</h1>
|
||||
<div class="spacer"></div>
|
||||
<button
|
||||
mat-flat-button
|
||||
(click)="createNewUser()"
|
||||
aria-label="Create new user"
|
||||
color="primary"
|
||||
>
|
||||
Create a Viewer User
|
||||
</button>
|
||||
<div class="console-app__users-header-buttons">
|
||||
<button
|
||||
class="console-app__users-header-add"
|
||||
mat-stroked-button
|
||||
(click)="addExistingUser()"
|
||||
aria-label="Create new user"
|
||||
color="primary"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
Add existing user
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
(click)="createNewUser()"
|
||||
aria-label="Create new user"
|
||||
color="primary"
|
||||
>
|
||||
Create a Viewer User
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<mat-table
|
||||
[dataSource]="dataSource"
|
||||
class="mat-elevation-z0"
|
||||
class="console-app__users-table"
|
||||
matSort
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="let column of columns"
|
||||
[matColumnDef]="column.columnDef"
|
||||
>
|
||||
<mat-header-cell *matHeaderCellDef>
|
||||
{{ column.header }}
|
||||
</mat-header-cell>
|
||||
<mat-cell
|
||||
*matCellDef="let row"
|
||||
[innerHTML]="column.cell(row)"
|
||||
></mat-cell>
|
||||
</ng-container>
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
(click)="openDetails(row.emailAddress)"
|
||||
></mat-row>
|
||||
</mat-table>
|
||||
<app-users-list
|
||||
[users]="usersService.users()"
|
||||
(onSelect)="openDetails($event)"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</app-selected-registrar-wrapper>
|
||||
|
||||
@@ -13,26 +13,37 @@
|
||||
// limitations under the License.
|
||||
|
||||
.console-app {
|
||||
&__users {
|
||||
max-width: 1024px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
&__users-spinner {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
$min-width: 756px;
|
||||
$max-width: 1024px;
|
||||
|
||||
&__users-table {
|
||||
min-width: $min-width !important;
|
||||
max-width: $max-width;
|
||||
}
|
||||
|
||||
&__users-new {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
&__users-add-existing {
|
||||
margin-top: 20px;
|
||||
> button {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
&__users-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
&-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
button {
|
||||
margin: 0 15px 15px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,29 +14,18 @@
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, effect, ViewChild } from '@angular/core';
|
||||
import { Component, effect } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { SelectedRegistrarModule } from '../app.module';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { RegistrarService } from '../registrar/registrar.service';
|
||||
import { SnackBarModule } from '../snackbar.module';
|
||||
import { UserEditComponent } from './userEdit.component';
|
||||
import { roleToDescription, User, UsersService } from './users.service';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
columnDef: 'emailAddress',
|
||||
header: 'User email',
|
||||
cell: (record: User) => `${record.emailAddress || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'role',
|
||||
header: 'User role',
|
||||
cell: (record: User) => `${roleToDescription(record.role)}`,
|
||||
},
|
||||
];
|
||||
import { User, UsersService } from './users.service';
|
||||
import { UserDataService } from '../shared/services/userData.service';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { UsersListComponent } from './usersList.component';
|
||||
import { MatSelectChange } from '@angular/material/select';
|
||||
|
||||
@Component({
|
||||
selector: 'app-users',
|
||||
@@ -44,41 +33,45 @@ export const columns = [
|
||||
styleUrls: ['./users.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
FormsModule,
|
||||
MaterialModule,
|
||||
SnackBarModule,
|
||||
CommonModule,
|
||||
SelectedRegistrarModule,
|
||||
UsersListComponent,
|
||||
UserEditComponent,
|
||||
],
|
||||
providers: [UsersService],
|
||||
})
|
||||
export class UsersComponent {
|
||||
dataSource: MatTableDataSource<User>;
|
||||
columns = columns;
|
||||
displayedColumns = this.columns.map((c) => c.columnDef);
|
||||
isLoading = false;
|
||||
|
||||
@ViewChild(MatSort) sort!: MatSort;
|
||||
selectingExistingUser = false;
|
||||
selectedRegistrarId = '';
|
||||
usersSelection: User[] = [];
|
||||
selectedExistingUser: User | undefined;
|
||||
|
||||
constructor(
|
||||
protected registrarService: RegistrarService,
|
||||
protected usersService: UsersService,
|
||||
private userDataService: UserDataService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
this.dataSource = new MatTableDataSource<User>(usersService.users());
|
||||
|
||||
effect(() => {
|
||||
if (registrarService.registrarId()) {
|
||||
this.loadUsers();
|
||||
}
|
||||
});
|
||||
effect(() => {
|
||||
this.dataSource.data = usersService.users();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.dataSource.sort = this.sort;
|
||||
addExistingUser() {
|
||||
this.selectingExistingUser = true;
|
||||
this.selectedRegistrarId = '';
|
||||
this.usersSelection = [];
|
||||
this.selectedExistingUser = undefined;
|
||||
}
|
||||
|
||||
existingUserSelected(user: User) {
|
||||
this.selectedExistingUser = user;
|
||||
}
|
||||
|
||||
loadUsers() {
|
||||
@@ -96,7 +89,7 @@ export class UsersComponent {
|
||||
|
||||
createNewUser() {
|
||||
this.isLoading = true;
|
||||
this.usersService.createNewUser().subscribe({
|
||||
this.usersService.createOrAddNewUser(null).subscribe({
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error || err.message);
|
||||
this.isLoading = false;
|
||||
@@ -107,7 +100,39 @@ export class UsersComponent {
|
||||
});
|
||||
}
|
||||
|
||||
openDetails(emailAddress: string) {
|
||||
this.usersService.currentlyOpenUserEmail.set(emailAddress);
|
||||
openDetails(user: User) {
|
||||
this.usersService.currentlyOpenUserEmail.set(user.emailAddress);
|
||||
}
|
||||
|
||||
onRegistrarSelectionChange(e: MatSelectChange) {
|
||||
if (e.value) {
|
||||
this.usersService.fetchUsersForRegistrar(e.value).subscribe({
|
||||
error: (err) => {
|
||||
this._snackBar.open(err.error || err.message);
|
||||
},
|
||||
next: (users) => {
|
||||
this.usersSelection = users;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
submitExistingUser() {
|
||||
this.isLoading = true;
|
||||
if (this.selectedExistingUser) {
|
||||
this.usersService
|
||||
.createOrAddNewUser(this.selectedExistingUser)
|
||||
.subscribe({
|
||||
error: (err) => {
|
||||
this._snackBar.open(err.error || err.message);
|
||||
this.isLoading = false;
|
||||
},
|
||||
complete: () => {
|
||||
this.isLoading = false;
|
||||
this.selectingExistingUser = false;
|
||||
this.loadUsers();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ export class UsersService {
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
fetchUsersForRegistrar(registrarId: string) {
|
||||
return this.backendService.getUsers(registrarId);
|
||||
}
|
||||
|
||||
fetchUsers() {
|
||||
return this.backendService
|
||||
.getUsers(this.registrarService.registrarId())
|
||||
@@ -56,14 +60,16 @@ export class UsersService {
|
||||
);
|
||||
}
|
||||
|
||||
createNewUser() {
|
||||
createOrAddNewUser(maybeExistingUser: User | null) {
|
||||
return this.backendService
|
||||
.createUser(this.registrarService.registrarId())
|
||||
.createUser(this.registrarService.registrarId(), maybeExistingUser)
|
||||
.pipe(
|
||||
tap((newUser: User) => {
|
||||
this.users.set([...this.users(), newUser]);
|
||||
this.currentlyOpenUserEmail.set(newUser.emailAddress);
|
||||
this.isNewUser = true;
|
||||
if (newUser) {
|
||||
this.users.set([...this.users(), newUser]);
|
||||
this.currentlyOpenUserEmail.set(newUser.emailAddress);
|
||||
this.isNewUser = true;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
24
console-webapp/src/app/users/usersList.component.html
Normal file
24
console-webapp/src/app/users/usersList.component.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="console-app__users-table-wrapper">
|
||||
<mat-table
|
||||
[dataSource]="dataSource"
|
||||
class="mat-elevation-z0"
|
||||
class="console-app__users-table"
|
||||
matSort
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="let column of columns"
|
||||
[matColumnDef]="column.columnDef"
|
||||
>
|
||||
<mat-header-cell *matHeaderCellDef>
|
||||
{{ column.header }}
|
||||
</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></mat-cell>
|
||||
</ng-container>
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
[class.rowSelected]="isRowSelected(row)"
|
||||
(click)="onClick(row)"
|
||||
></mat-row>
|
||||
</mat-table>
|
||||
</div>
|
||||
14
console-webapp/src/app/users/usersList.component.scss
Normal file
14
console-webapp/src/app/users/usersList.component.scss
Normal file
@@ -0,0 +1,14 @@
|
||||
.console-app {
|
||||
&__users-table {
|
||||
min-width: 616px;
|
||||
.rowSelected {
|
||||
background-color: var(--light-highlight);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
&__users-table-wrapper {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
78
console-webapp/src/app/users/usersList.component.ts
Normal file
78
console-webapp/src/app/users/usersList.component.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
effect,
|
||||
EventEmitter,
|
||||
input,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { User, roleToDescription } from './users.service';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
columnDef: 'emailAddress',
|
||||
header: 'User email',
|
||||
cell: (record: User) => `${record.emailAddress || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'role',
|
||||
header: 'User role',
|
||||
cell: (record: User) => `${roleToDescription(record.role)}`,
|
||||
},
|
||||
];
|
||||
|
||||
@Component({
|
||||
selector: 'app-users-list',
|
||||
templateUrl: './usersList.component.html',
|
||||
styleUrls: ['./usersList.component.scss'],
|
||||
standalone: true,
|
||||
imports: [MaterialModule, CommonModule],
|
||||
providers: [],
|
||||
})
|
||||
export class UsersListComponent {
|
||||
columns = columns;
|
||||
displayedColumns = this.columns.map((c) => c.columnDef);
|
||||
dataSource: MatTableDataSource<User>;
|
||||
selectedRow!: User;
|
||||
users = input<User[]>([]);
|
||||
@Output() onSelect = new EventEmitter<User>();
|
||||
@ViewChild(MatSort) sort!: MatSort;
|
||||
|
||||
constructor() {
|
||||
this.dataSource = new MatTableDataSource<User>(this.users());
|
||||
effect(() => {
|
||||
this.dataSource.data = this.users();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
onClick(row: User) {
|
||||
this.selectedRow = row;
|
||||
this.onSelect.emit(row);
|
||||
}
|
||||
|
||||
isRowSelected(row: User) {
|
||||
return row === this.selectedRow;
|
||||
}
|
||||
}
|
||||
@@ -1743,6 +1743,17 @@ public final class RegistryConfig {
|
||||
CONFIG_SETTINGS.get().registryPolicy.tieredPricingPromotionRegistrarIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set of registrars for which we do not send poll messages on standard domain deletion.
|
||||
*
|
||||
* <p>For these registrars we won't send a poll message in order to avoid database contention. See
|
||||
* b/379331882 for more details.
|
||||
*/
|
||||
public static ImmutableSet<String> getNoPollMessageOnDeletionRegistrarIds() {
|
||||
return ImmutableSet.copyOf(
|
||||
CONFIG_SETTINGS.get().registryPolicy.noPollMessageOnDeletionRegistrarIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memoizes loading of the {@link RegistryConfigSettings} POJO.
|
||||
*
|
||||
|
||||
@@ -115,6 +115,7 @@ public class RegistryConfigSettings {
|
||||
public boolean requireSslCertificates;
|
||||
public double sunriseDomainCreateDiscount;
|
||||
public Set<String> tieredPricingPromotionRegistrarIds;
|
||||
public Set<String> noPollMessageOnDeletionRegistrarIds;
|
||||
}
|
||||
|
||||
/** Configuration for Hibernate. */
|
||||
|
||||
@@ -220,6 +220,9 @@ registryPolicy:
|
||||
# In addition, we will return the non-promotional (i.e. incorrect) price on
|
||||
# domain create requests.
|
||||
tieredPricingPromotionRegistrarIds: []
|
||||
# List of registrars for which we won't send poll message on standard domain
|
||||
# deletions.
|
||||
noPollMessageOnDeletionRegistrarIds: []
|
||||
|
||||
hibernate:
|
||||
# If set to false, calls to tm().transact() cannot be nested. If set to true,
|
||||
|
||||
@@ -11,6 +11,8 @@ registryPolicy:
|
||||
Line 2 is this 1.
|
||||
tieredPricingPromotionRegistrarIds:
|
||||
- NewRegistrar
|
||||
noPollMessageOnDeletionRegistrarIds:
|
||||
- NewRegistrar
|
||||
|
||||
caching:
|
||||
singletonCacheRefreshSeconds: 0
|
||||
|
||||
@@ -105,7 +105,7 @@ public final class ExtensionManager {
|
||||
}
|
||||
|
||||
private static final ImmutableSet<EppRequestSource> ALLOWED_METADATA_EPP_REQUEST_SOURCES =
|
||||
ImmutableSet.of(EppRequestSource.TOOL, EppRequestSource.BACKEND);
|
||||
ImmutableSet.of(EppRequestSource.BACKEND, EppRequestSource.CONSOLE, EppRequestSource.TOOL);
|
||||
|
||||
private void checkForRestrictedExtensions(
|
||||
ImmutableSet<Class<? extends CommandExtension>> suppliedExtensions)
|
||||
|
||||
@@ -75,7 +75,8 @@ public class FlowRunner {
|
||||
flowReporter.recordToLogs();
|
||||
}
|
||||
eppMetricBuilder.setCommandNameFromFlow(flowClass.getSimpleName());
|
||||
if (!isTransactional) {
|
||||
// We may already be in a transaction, e.g., when invoked by DeleteExpiredDomainsAction.
|
||||
if (!isTransactional || jpaTransactionManager.inTransaction()) {
|
||||
return EppOutput.create(flowProvider.get().run());
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -44,7 +44,9 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.AssociationProhibitsOperationException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
@@ -117,6 +119,8 @@ import org.joda.time.Duration;
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_DELETE)
|
||||
public final class DomainDeleteFlow implements MutatingFlow {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES = ImmutableSet.of(
|
||||
StatusValue.CLIENT_DELETE_PROHIBITED,
|
||||
StatusValue.PENDING_DELETE,
|
||||
@@ -212,10 +216,17 @@ public final class DomainDeleteFlow implements MutatingFlow {
|
||||
// superuser (i.e. the registrar didn't request this delete and thus should be notified even if
|
||||
// it is synchronous).
|
||||
if (durationUntilDelete.isLongerThan(Duration.ZERO) || isSuperuser) {
|
||||
PollMessage.OneTime deletePollMessage =
|
||||
createDeletePollMessage(existingDomain, domainHistoryId, deletionTime);
|
||||
entitiesToSave.add(deletePollMessage);
|
||||
builder.setDeletePollMessage(deletePollMessage.createVKey());
|
||||
if (RegistryConfig.getNoPollMessageOnDeletionRegistrarIds()
|
||||
.contains(existingDomain.getCurrentSponsorRegistrarId())) {
|
||||
logger.atInfo().log(
|
||||
"Skipping poll message on domain deletion for registrar %s due to configuration",
|
||||
existingDomain.getCurrentSponsorRegistrarId());
|
||||
} else {
|
||||
PollMessage.OneTime deletePollMessage =
|
||||
createDeletePollMessage(existingDomain, domainHistoryId, deletionTime);
|
||||
entitiesToSave.add(deletePollMessage);
|
||||
builder.setDeletePollMessage(deletePollMessage.createVKey());
|
||||
}
|
||||
}
|
||||
|
||||
// Send a second poll message immediately if the domain is being deleted asynchronously by a
|
||||
|
||||
@@ -183,7 +183,9 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
DomainHistory domainHistory = buildDomainHistory(newDomain, now);
|
||||
entitiesToSave.add(newDomain, domainHistory, autorenewEvent, autorenewPollMessage);
|
||||
tm().putAll(entitiesToSave.build());
|
||||
tm().delete(existingDomain.getDeletePollMessage());
|
||||
if (existingDomain.getDeletePollMessage() != null) {
|
||||
tm().delete(existingDomain.getDeletePollMessage());
|
||||
}
|
||||
requestDomainDnsRefresh(existingDomain.getDomainName());
|
||||
return responseBuilder
|
||||
.setExtensions(createResponseExtensions(feesAndCredits, feeUpdate, isExpired))
|
||||
|
||||
@@ -37,6 +37,8 @@ import google.registry.model.poll.MessageQueueInfo;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.poll.PollMessageExternalKeyConverter;
|
||||
import google.registry.model.poll.PollMessageExternalKeyConverter.PollMessageExternalKeyParseException;
|
||||
import google.registry.persistence.IsolationLevel;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
@@ -55,6 +57,7 @@ import org.joda.time.DateTime;
|
||||
* @error {@link PollAckFlow.MissingMessageIdException}
|
||||
* @error {@link PollAckFlow.NotAuthorizedToAckMessageException}
|
||||
*/
|
||||
@IsolationLevel(value = TransactionIsolationLevel.TRANSACTION_READ_COMMITTED)
|
||||
public final class PollAckFlow implements MutatingFlow {
|
||||
|
||||
@Inject ExtensionManager extensionManager;
|
||||
|
||||
@@ -32,6 +32,8 @@ import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.poll.MessageQueueInfo;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.poll.PollMessageExternalKeyConverter;
|
||||
import google.registry.persistence.IsolationLevel;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -47,6 +49,7 @@ import org.joda.time.DateTime;
|
||||
*
|
||||
* @error {@link PollRequestFlow.UnexpectedMessageIdException}
|
||||
*/
|
||||
@IsolationLevel(value = TransactionIsolationLevel.TRANSACTION_READ_COMMITTED)
|
||||
public final class PollRequestFlow implements TransactionalFlow {
|
||||
|
||||
@Inject ExtensionManager extensionManager;
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.ui.server.console;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.Action.Method.DELETE;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
@@ -36,6 +37,7 @@ import google.registry.batch.CloudTasksUtils;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.export.sheet.SyncRegistrarsSheetAction;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.ConsoleUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
@@ -260,6 +262,14 @@ public abstract class ConsoleApiAction implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
protected void finishAndPersistConsoleUpdateHistory(ConsoleUpdateHistory.Builder<?, ?> builder) {
|
||||
builder.setActingUser(consoleApiParams.authResult().user().get());
|
||||
builder.setUrl(consoleApiParams.request().getRequestURI());
|
||||
builder.setMethod(consoleApiParams.request().getMethod());
|
||||
builder.setModificationTime(tm().getTransactionTime());
|
||||
tm().put(builder.build());
|
||||
}
|
||||
|
||||
/** Specialized exception class used for failure when a user doesn't have the right permission. */
|
||||
private static class ConsolePermissionForbiddenException extends RuntimeException {
|
||||
private ConsolePermissionForbiddenException(String message) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
@@ -26,13 +27,16 @@ public record ConsoleApiParams(
|
||||
Response response,
|
||||
AuthResult authResult,
|
||||
SendEmailUtils sendEmailUtils,
|
||||
XsrfTokenManager xsrfTokenManager) {
|
||||
XsrfTokenManager xsrfTokenManager,
|
||||
Gson gson) {
|
||||
public static ConsoleApiParams create(
|
||||
HttpServletRequest request,
|
||||
Response response,
|
||||
AuthResult authResult,
|
||||
SendEmailUtils sendEmailUtils,
|
||||
XsrfTokenManager xsrfTokenManager) {
|
||||
return new ConsoleApiParams(request, response, authResult, sendEmailUtils, xsrfTokenManager);
|
||||
XsrfTokenManager xsrfTokenManager,
|
||||
Gson gson) {
|
||||
return new ConsoleApiParams(
|
||||
request, response, authResult, sendEmailUtils, xsrfTokenManager, gson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
// Copyright 2024 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.ui.server.console;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.escape.Escaper;
|
||||
import com.google.common.xml.XmlEscapers;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.flows.EppController;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
import google.registry.flows.StatelessRequestSessionMetadata;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.Result;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.OptionalJsonPayload;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Console endpoint to perform the same action to a list of domains.
|
||||
*
|
||||
* <p>All requests must include the {@link BulkAction} to perform as well as a {@link
|
||||
* BulkDomainList} of domains on which to apply the action. The remaining contents of the request
|
||||
* body depend on the type of action -- some requests may require more data than others.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.GaeService.DEFAULT,
|
||||
gkeService = Action.GkeService.CONSOLE,
|
||||
path = ConsoleBulkDomainAction.PATH,
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public class ConsoleBulkDomainAction extends ConsoleApiAction {
|
||||
|
||||
public static final String PATH = "/console-api/bulk-domain";
|
||||
|
||||
private static Escaper XML_ESCAPER = XmlEscapers.xmlContentEscaper();
|
||||
|
||||
public enum BulkAction {
|
||||
DELETE,
|
||||
SUSPEND
|
||||
}
|
||||
|
||||
/** All requests must include at least a list of domain names on which to perform the action. */
|
||||
public record BulkDomainList(@Expose List<String> domainList) {}
|
||||
|
||||
public record BulkDomainDeleteRequest(@Expose String reason) {}
|
||||
|
||||
public record BulkDomainSuspendRequest(@Expose String reason) {}
|
||||
|
||||
private static final String DOMAIN_DELETE_XML =
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<delete>
|
||||
<domain:delete
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN_NAME%</domain:name>
|
||||
</domain:delete>
|
||||
</delete>
|
||||
<extension>
|
||||
<metadata:metadata xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
|
||||
<metadata:reason>%REASON%</metadata:reason>
|
||||
<metadata:requestedByRegistrar>true</metadata:requestedByRegistrar>
|
||||
</metadata:metadata>
|
||||
</extension>
|
||||
<clTRID>RegistryConsole</clTRID>
|
||||
</command>
|
||||
</epp>""";
|
||||
|
||||
private static final String DOMAIN_SUSPEND_XML =
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp
|
||||
xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN_NAME%</domain:name>
|
||||
<domain:add>
|
||||
<domain:status s="serverDeleteProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverHold" lang="en"></domain:status>
|
||||
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverTransferProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverUpdateProhibited" lang="en"></domain:status>
|
||||
</domain:add>
|
||||
<domain:rem></domain:rem>
|
||||
</domain:update>
|
||||
</update>
|
||||
<extension>
|
||||
<metadata:metadata
|
||||
xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
|
||||
<metadata:reason>Console suspension: %REASON%</metadata:reason>
|
||||
<metadata:requestedByRegistrar>false</metadata:requestedByRegistrar>
|
||||
</metadata:metadata>
|
||||
</extension>
|
||||
<clTRID>RegistryTool</clTRID>
|
||||
</command>
|
||||
</epp>""";
|
||||
|
||||
private final EppController eppController;
|
||||
private final String registrarId;
|
||||
private final String bulkDomainAction;
|
||||
private final Optional<JsonElement> optionalJsonPayload;
|
||||
|
||||
@Inject
|
||||
public ConsoleBulkDomainAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
EppController eppController,
|
||||
@Parameter("registrarId") String registrarId,
|
||||
@Parameter("bulkDomainAction") String bulkDomainAction,
|
||||
@OptionalJsonPayload Optional<JsonElement> optionalJsonPayload) {
|
||||
super(consoleApiParams);
|
||||
this.eppController = eppController;
|
||||
this.registrarId = registrarId;
|
||||
this.bulkDomainAction = bulkDomainAction;
|
||||
this.optionalJsonPayload = optionalJsonPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postHandler(User user) {
|
||||
BulkAction bulkAction = BulkAction.valueOf(bulkDomainAction);
|
||||
JsonElement jsonPayload =
|
||||
optionalJsonPayload.orElseThrow(
|
||||
() -> new IllegalArgumentException("Bulk action payload must be present"));
|
||||
BulkDomainList domainList = consoleApiParams.gson().fromJson(jsonPayload, BulkDomainList.class);
|
||||
checkPermission(user, registrarId, ConsolePermission.EXECUTE_EPP_COMMANDS);
|
||||
ImmutableMap<String, ConsoleEppOutput> result =
|
||||
switch (bulkAction) {
|
||||
case DELETE -> handleBulkDelete(jsonPayload, domainList, user);
|
||||
case SUSPEND -> handleBulkSuspend(jsonPayload, domainList, user);
|
||||
};
|
||||
// Front end should parse situations where only some commands worked
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(result));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
private ImmutableMap<String, ConsoleEppOutput> handleBulkDelete(
|
||||
JsonElement jsonPayload, BulkDomainList domainList, User user) {
|
||||
String reason =
|
||||
consoleApiParams.gson().fromJson(jsonPayload, BulkDomainDeleteRequest.class).reason;
|
||||
return runCommandOverDomains(
|
||||
domainList,
|
||||
DOMAIN_DELETE_XML,
|
||||
new ImmutableMap.Builder<String, String>().put("REASON", reason),
|
||||
user);
|
||||
}
|
||||
|
||||
private ImmutableMap<String, ConsoleEppOutput> handleBulkSuspend(
|
||||
JsonElement jsonPayload, BulkDomainList domainList, User user) {
|
||||
String reason =
|
||||
consoleApiParams.gson().fromJson(jsonPayload, BulkDomainSuspendRequest.class).reason;
|
||||
return runCommandOverDomains(
|
||||
domainList,
|
||||
DOMAIN_SUSPEND_XML,
|
||||
new ImmutableMap.Builder<String, String>().put("REASON", reason),
|
||||
user);
|
||||
}
|
||||
|
||||
/** Runs the provided XML template and substitutions over a provided list of domains. */
|
||||
private ImmutableMap<String, ConsoleEppOutput> runCommandOverDomains(
|
||||
BulkDomainList domainList,
|
||||
String xmlTemplate,
|
||||
ImmutableMap.Builder<String, String> replacements,
|
||||
User user) {
|
||||
return domainList.domainList.stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
d -> d,
|
||||
d ->
|
||||
executeEpp(
|
||||
fillSubstitutions(xmlTemplate, replacements.put("DOMAIN_NAME", d)), user)));
|
||||
}
|
||||
|
||||
private ConsoleEppOutput executeEpp(String xml, User user) {
|
||||
return ConsoleEppOutput.fromEppOutput(
|
||||
eppController.handleEppCommand(
|
||||
new StatelessRequestSessionMetadata(
|
||||
registrarId, ProtocolDefinition.getVisibleServiceExtensionUris()),
|
||||
new PasswordOnlyTransportCredentials(),
|
||||
EppRequestSource.CONSOLE,
|
||||
false,
|
||||
user.getUserRoles().isAdmin(),
|
||||
xml.getBytes(UTF_8)));
|
||||
}
|
||||
|
||||
/** Fills the provided XML template with the replacement values, including escaping the values. */
|
||||
private String fillSubstitutions(
|
||||
String xmlTemplate, ImmutableMap.Builder<String, String> replacements) {
|
||||
String xml = xmlTemplate;
|
||||
for (Map.Entry<String, String> entry : replacements.buildKeepingLast().entrySet()) {
|
||||
xml = xml.replaceAll("%" + entry.getKey() + "%", XML_ESCAPER.escape(entry.getValue()));
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
public record ConsoleEppOutput(@Expose String message, @Expose int responseCode) {
|
||||
static ConsoleEppOutput fromEppOutput(EppOutput eppOutput) {
|
||||
Result result = eppOutput.getResponse().getResult();
|
||||
return new ConsoleEppOutput(result.getMsg(), result.getCode().code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.EppResourceUtils;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
@@ -41,17 +40,14 @@ public class ConsoleDomainGetAction extends ConsoleApiAction {
|
||||
|
||||
public static final String PATH = "/console-api/domain";
|
||||
|
||||
private final Gson gson;
|
||||
private final String paramDomain;
|
||||
|
||||
@Inject
|
||||
public ConsoleDomainGetAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
Gson gson,
|
||||
@Parameter("consoleDomain") String paramDomain) {
|
||||
super(consoleApiParams);
|
||||
this.paramDomain = paramDomain;
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,6 +68,6 @@ public class ConsoleDomainGetAction extends ConsoleApiAction {
|
||||
return;
|
||||
}
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
consoleApiParams.response().setPayload(gson.toJson(domain));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(domain));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.console.User;
|
||||
@@ -55,7 +54,6 @@ public class ConsoleDomainListAction extends ConsoleApiAction {
|
||||
private static final String SEARCH_TERM_QUERY = " AND LOWER(domainName) LIKE :searchTerm";
|
||||
private static final String ORDER_BY_STATEMENT = " ORDER BY creationTime DESC";
|
||||
|
||||
private final Gson gson;
|
||||
private final String registrarId;
|
||||
private final Optional<DateTime> checkpointTime;
|
||||
private final int pageNumber;
|
||||
@@ -66,7 +64,6 @@ public class ConsoleDomainListAction extends ConsoleApiAction {
|
||||
@Inject
|
||||
public ConsoleDomainListAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
Gson gson,
|
||||
@Parameter("registrarId") String registrarId,
|
||||
@Parameter("checkpointTime") Optional<DateTime> checkpointTime,
|
||||
@Parameter("pageNumber") Optional<Integer> pageNumber,
|
||||
@@ -74,7 +71,6 @@ public class ConsoleDomainListAction extends ConsoleApiAction {
|
||||
@Parameter("totalResults") Optional<Long> totalResults,
|
||||
@Parameter("searchTerm") Optional<String> searchTerm) {
|
||||
super(consoleApiParams);
|
||||
this.gson = gson;
|
||||
this.registrarId = registrarId;
|
||||
this.checkpointTime = checkpointTime;
|
||||
this.pageNumber = pageNumber.orElse(0);
|
||||
@@ -120,7 +116,10 @@ public class ConsoleDomainListAction extends ConsoleApiAction {
|
||||
|
||||
consoleApiParams
|
||||
.response()
|
||||
.setPayload(gson.toJson(new DomainListResult(domains, checkpoint, actualTotalResults)));
|
||||
.setPayload(
|
||||
consoleApiParams
|
||||
.gson()
|
||||
.toJson(new DomainListResult(domains, checkpoint, actualTotalResults)));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.flows.EppException.AuthenticationErrorException;
|
||||
import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
import google.registry.model.console.ConsoleUpdateHistory;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
@@ -53,7 +55,6 @@ public class ConsoleEppPasswordAction extends ConsoleApiAction {
|
||||
private final PasswordOnlyTransportCredentials credentials =
|
||||
new PasswordOnlyTransportCredentials();
|
||||
private final AuthenticatedRegistrarAccessor registrarAccessor;
|
||||
|
||||
private final Optional<EppPasswordData> eppPasswordChangeRequest;
|
||||
|
||||
@Inject
|
||||
@@ -106,6 +107,14 @@ public class ConsoleEppPasswordAction extends ConsoleApiAction {
|
||||
Registrar updatedRegistrar =
|
||||
registrar.asBuilder().setPassword(eppRequestBody.newPassword()).build();
|
||||
tm().put(updatedRegistrar);
|
||||
EppPasswordData sanitizedData =
|
||||
new EppPasswordData(
|
||||
eppRequestBody.registrarId, "********", "••••••••", "••••••••");
|
||||
finishAndPersistConsoleUpdateHistory(
|
||||
new RegistrarUpdateHistory.Builder()
|
||||
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
|
||||
.setRegistrar(updatedRegistrar)
|
||||
.setRequestBody(consoleApiParams.gson().toJson(sanitizedData)));
|
||||
sendExternalUpdates(
|
||||
ImmutableMap.of("password", new DiffUtils.DiffPair("********", "••••••••")),
|
||||
registrar,
|
||||
|
||||
@@ -53,8 +53,10 @@ public final class ConsoleModule {
|
||||
Response response,
|
||||
AuthResult authResult,
|
||||
SendEmailUtils sendEmailUtils,
|
||||
XsrfTokenManager xsrfTokenManager) {
|
||||
return ConsoleApiParams.create(request, response, authResult, sendEmailUtils, xsrfTokenManager);
|
||||
XsrfTokenManager xsrfTokenManager,
|
||||
Gson gson) {
|
||||
return ConsoleApiParams.create(
|
||||
request, response, authResult, sendEmailUtils, xsrfTokenManager, gson);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -239,6 +241,12 @@ public final class ConsoleModule {
|
||||
return extractOptionalParameter(req, "searchTerm");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("bulkDomainAction")
|
||||
public static String provideBulkDomainAction(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, "bulkDomainAction");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("eppPasswordChangeRequest")
|
||||
public static Optional<EppPasswordData> provideEppPasswordChangeRequest(
|
||||
|
||||
@@ -27,7 +27,6 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.OteAccountBuilder;
|
||||
@@ -62,7 +61,6 @@ public class ConsoleOteAction extends ConsoleApiAction {
|
||||
private static final String STAT_TYPE_DESCRIPTION_PARAM = "description";
|
||||
private static final String STAT_TYPE_REQUIREMENT_PARAM = "requirement";
|
||||
private static final String STAT_TYPE_TIMES_PERFORMED_PARAM = "timesPerformed";
|
||||
private final Gson gson;
|
||||
private final StringGenerator passwordGenerator;
|
||||
private final Optional<OteCreateData> oteCreateData;
|
||||
private final Optional<String> maybeGroupEmailAddress;
|
||||
@@ -72,14 +70,12 @@ public class ConsoleOteAction extends ConsoleApiAction {
|
||||
@Inject
|
||||
public ConsoleOteAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
Gson gson,
|
||||
IamClient iamClient,
|
||||
@Parameter("registrarId") String registrarId, // Get request param
|
||||
@Config("gSuiteConsoleUserGroupEmailAddress") Optional<String> maybeGroupEmailAddress,
|
||||
@Named("base58StringGenerator") StringGenerator passwordGenerator,
|
||||
@Parameter("oteCreateData") Optional<OteCreateData> oteCreateData) {
|
||||
super(consoleApiParams);
|
||||
this.gson = gson;
|
||||
this.passwordGenerator = passwordGenerator;
|
||||
this.oteCreateData = oteCreateData;
|
||||
this.maybeGroupEmailAddress = maybeGroupEmailAddress;
|
||||
@@ -116,8 +112,13 @@ public class ConsoleOteAction extends ConsoleApiAction {
|
||||
consoleApiParams
|
||||
.response()
|
||||
.setPayload(
|
||||
gson.toJson(
|
||||
ImmutableMap.builder().putAll(registrarIdToTld).put("password", password).build()));
|
||||
consoleApiParams
|
||||
.gson()
|
||||
.toJson(
|
||||
ImmutableMap.builder()
|
||||
.putAll(registrarIdToTld)
|
||||
.put("password", password)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,7 +154,7 @@ public class ConsoleOteAction extends ConsoleApiAction {
|
||||
convertSingleRequirement(statType, oteStats.getCount(statType)))
|
||||
.collect(toImmutableList());
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
consoleApiParams.response().setPayload(gson.toJson(stats));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(stats));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.domain.DomainFlowUtils;
|
||||
@@ -72,7 +71,6 @@ public class ConsoleRegistryLockAction extends ConsoleApiAction {
|
||||
|
||||
private final DomainLockUtils domainLockUtils;
|
||||
private final GmailClient gmailClient;
|
||||
private final Gson gson;
|
||||
private final Optional<ConsoleRegistryLockPostInput> optionalPostInput;
|
||||
private final String registrarId;
|
||||
|
||||
@@ -81,14 +79,12 @@ public class ConsoleRegistryLockAction extends ConsoleApiAction {
|
||||
ConsoleApiParams consoleApiParams,
|
||||
DomainLockUtils domainLockUtils,
|
||||
GmailClient gmailClient,
|
||||
Gson gson,
|
||||
@Parameter("consoleRegistryLockPostInput")
|
||||
Optional<ConsoleRegistryLockPostInput> optionalPostInput,
|
||||
@Parameter("registrarId") String registrarId) {
|
||||
super(consoleApiParams);
|
||||
this.domainLockUtils = domainLockUtils;
|
||||
this.gmailClient = gmailClient;
|
||||
this.gson = gson;
|
||||
this.optionalPostInput = optionalPostInput;
|
||||
this.registrarId = registrarId;
|
||||
}
|
||||
@@ -96,7 +92,7 @@ public class ConsoleRegistryLockAction extends ConsoleApiAction {
|
||||
@Override
|
||||
protected void getHandler(User user) {
|
||||
checkPermission(user, registrarId, ConsolePermission.REGISTRY_LOCK);
|
||||
consoleApiParams.response().setPayload(gson.toJson(getLockedDomains()));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(getLockedDomains()));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package google.registry.ui.server.console;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.domain.RegistryLock;
|
||||
@@ -42,18 +41,15 @@ public class ConsoleRegistryLockVerifyAction extends ConsoleApiAction {
|
||||
static final String PATH = "/console-api/registry-lock-verify";
|
||||
|
||||
private final DomainLockUtils domainLockUtils;
|
||||
private final Gson gson;
|
||||
private final String lockVerificationCode;
|
||||
|
||||
@Inject
|
||||
public ConsoleRegistryLockVerifyAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
DomainLockUtils domainLockUtils,
|
||||
Gson gson,
|
||||
@Parameter("lockVerificationCode") String lockVerificationCode) {
|
||||
super(consoleApiParams);
|
||||
this.domainLockUtils = domainLockUtils;
|
||||
this.gson = gson;
|
||||
this.lockVerificationCode = lockVerificationCode;
|
||||
}
|
||||
|
||||
@@ -68,7 +64,7 @@ public class ConsoleRegistryLockVerifyAction extends ConsoleApiAction {
|
||||
RegistryLockVerificationResponse lockResponse =
|
||||
new RegistryLockVerificationResponse(
|
||||
Ascii.toLowerCase(action.toString()), lock.getDomainName(), lock.getRegistrarId());
|
||||
consoleApiParams.response().setPayload(gson.toJson(lockResponse));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(lockResponse));
|
||||
consoleApiParams.response().setStatus(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ import static org.apache.http.HttpStatus.SC_OK;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.ConsoleUpdateHistory;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
@@ -99,6 +101,11 @@ public class ConsoleUpdateRegistrarAction extends ConsoleApiAction {
|
||||
.build();
|
||||
|
||||
tm().put(updatedRegistrar);
|
||||
finishAndPersistConsoleUpdateHistory(
|
||||
new RegistrarUpdateHistory.Builder()
|
||||
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
|
||||
.setRegistrar(updatedRegistrar)
|
||||
.setRequestBody(consoleApiParams.gson().toJson(registrarParam)));
|
||||
sendExternalUpdatesIfNecessary(
|
||||
EmailInfo.create(
|
||||
existingRegistrar.get(),
|
||||
|
||||
@@ -82,6 +82,8 @@ public class ConsoleUserDataAction extends ConsoleApiAction {
|
||||
// auth checks.
|
||||
"isAdmin", user.getUserRoles().isAdmin(),
|
||||
"globalRole", user.getUserRoles().getGlobalRole(),
|
||||
// registrar-specific roles
|
||||
"userRoles", user.getUserRoles().getRegistrarRoles(),
|
||||
// Include static contact resources in this call to minimize round trips
|
||||
"productName", productName,
|
||||
"supportEmail", supportEmail,
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.google.api.services.directory.model.UserName;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
@@ -49,6 +48,8 @@ import google.registry.tools.IamClient;
|
||||
import google.registry.util.StringGenerator;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
@@ -64,10 +65,10 @@ import javax.inject.Named;
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
static final String PATH = "/console-api/users";
|
||||
private static final int PASSWORD_LENGTH = 16;
|
||||
|
||||
private static final int PASSWORD_LENGTH = 16;
|
||||
private static final Splitter EMAIL_SPLITTER = Splitter.on('@').trimResults();
|
||||
private final Gson gson;
|
||||
|
||||
private final String registrarId;
|
||||
private final Directory directory;
|
||||
private final StringGenerator passwordGenerator;
|
||||
@@ -79,7 +80,6 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
@Inject
|
||||
public ConsoleUsersAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
Gson gson,
|
||||
Directory directory,
|
||||
IamClient iamClient,
|
||||
@Config("gSuiteDomainName") String gSuiteDomainName,
|
||||
@@ -88,7 +88,6 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
@Parameter("userData") Optional<UserData> userData,
|
||||
@Parameter("registrarId") String registrarId) {
|
||||
super(consoleApiParams);
|
||||
this.gson = gson;
|
||||
this.registrarId = registrarId;
|
||||
this.directory = directory;
|
||||
this.passwordGenerator = passwordGenerator;
|
||||
@@ -103,7 +102,12 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
// Temporary flag while testing
|
||||
if (user.getUserRoles().isAdmin()) {
|
||||
checkPermission(user, registrarId, ConsolePermission.MANAGE_USERS);
|
||||
tm().transact(() -> runCreateInTransaction());
|
||||
if (userData.isPresent()) { // Adding existing user to registrar
|
||||
tm().transact(this::runAppendUserInTransaction);
|
||||
} else { // Adding new user to registrar
|
||||
tm().transact(this::runCreateInTransaction);
|
||||
}
|
||||
|
||||
} else {
|
||||
consoleApiParams.response().setStatus(SC_FORBIDDEN);
|
||||
}
|
||||
@@ -114,7 +118,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
// Temporary flag while testing
|
||||
if (user.getUserRoles().isAdmin()) {
|
||||
checkPermission(user, registrarId, ConsolePermission.MANAGE_USERS);
|
||||
tm().transact(() -> runUpdateInTransaction());
|
||||
tm().transact(this::runUpdateInTransaction);
|
||||
} else {
|
||||
consoleApiParams.response().setStatus(SC_FORBIDDEN);
|
||||
}
|
||||
@@ -133,7 +137,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
null))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
consoleApiParams.response().setPayload(gson.toJson(users));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(users));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
@@ -142,27 +146,52 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
// Temporary flag while testing
|
||||
if (user.getUserRoles().isAdmin()) {
|
||||
checkPermission(user, registrarId, ConsolePermission.MANAGE_USERS);
|
||||
tm().transact(() -> runDeleteInTransaction());
|
||||
tm().transact(this::runDeleteInTransaction);
|
||||
} else {
|
||||
consoleApiParams.response().setStatus(SC_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
private void runDeleteInTransaction() throws IOException {
|
||||
if (!isModifyingRequestValid()) {
|
||||
private void runAppendUserInTransaction() {
|
||||
if (!isModifyingRequestValid(false)) {
|
||||
return;
|
||||
}
|
||||
String email = this.userData.get().emailAddress;
|
||||
try {
|
||||
directory.users().delete(email).execute();
|
||||
} catch (IOException e) {
|
||||
setFailedResponse("Failed to delete the user workspace account", SC_INTERNAL_SERVER_ERROR);
|
||||
throw e;
|
||||
ImmutableList<User> allRegistrarUsers = getAllRegistrarUsers(registrarId);
|
||||
if (allRegistrarUsers.size() >= 4)
|
||||
throw new BadRequestException("Total users amount per registrar is limited to 4");
|
||||
|
||||
updateUserRegistrarRoles(
|
||||
this.userData.get().emailAddress,
|
||||
registrarId,
|
||||
RegistrarRole.valueOf(this.userData.get().role),
|
||||
false);
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
private void runDeleteInTransaction() throws IOException {
|
||||
if (!isModifyingRequestValid(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String email = this.userData.get().emailAddress;
|
||||
User updatedUser =
|
||||
updateUserRegistrarRoles(
|
||||
email, registrarId, RegistrarRole.valueOf(this.userData.get().role), true);
|
||||
|
||||
// User has no registrars assigned
|
||||
if (updatedUser.getUserRoles().getRegistrarRoles().size() == 0) {
|
||||
try {
|
||||
directory.users().delete(email).execute();
|
||||
} catch (IOException e) {
|
||||
setFailedResponse("Failed to delete the user workspace account", SC_INTERNAL_SERVER_ERROR);
|
||||
throw e;
|
||||
}
|
||||
|
||||
VKey<User> key = VKey.create(User.class, email);
|
||||
tm().delete(key);
|
||||
User.revokeIapPermission(email, maybeGroupEmailAddress, cloudTasksUtils, null, iamClient);
|
||||
}
|
||||
|
||||
VKey<User> key = VKey.create(User.class, email);
|
||||
tm().delete(key);
|
||||
User.revokeIapPermission(email, maybeGroupEmailAddress, cloudTasksUtils, null, iamClient);
|
||||
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
@@ -213,33 +242,29 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
consoleApiParams
|
||||
.response()
|
||||
.setPayload(
|
||||
gson.toJson(
|
||||
new UserData(
|
||||
newUser.getPrimaryEmail(), ACCOUNT_MANAGER.toString(), newUser.getPassword())));
|
||||
consoleApiParams
|
||||
.gson()
|
||||
.toJson(
|
||||
new UserData(
|
||||
newUser.getPrimaryEmail(),
|
||||
ACCOUNT_MANAGER.toString(),
|
||||
newUser.getPassword())));
|
||||
}
|
||||
|
||||
private void runUpdateInTransaction() {
|
||||
if (!isModifyingRequestValid()) {
|
||||
if (!isModifyingRequestValid(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserData userData = this.userData.get();
|
||||
UserRoles userRoles =
|
||||
new UserRoles.Builder()
|
||||
.setRegistrarRoles(ImmutableMap.of(registrarId, RegistrarRole.valueOf(userData.role)))
|
||||
.build();
|
||||
User updatedUser =
|
||||
tm().loadByKeyIfPresent(VKey.create(User.class, userData.emailAddress))
|
||||
.get()
|
||||
.asBuilder()
|
||||
.setUserRoles(userRoles)
|
||||
.build();
|
||||
|
||||
tm().put(updatedUser);
|
||||
updateUserRegistrarRoles(
|
||||
this.userData.get().emailAddress,
|
||||
registrarId,
|
||||
RegistrarRole.valueOf(this.userData.get().role),
|
||||
false);
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
private boolean isModifyingRequestValid() {
|
||||
private boolean isModifyingRequestValid(boolean verifyAccess) {
|
||||
if (userData.isEmpty()
|
||||
|| isNullOrEmpty(userData.get().emailAddress)
|
||||
|| isNullOrEmpty(userData.get().role)) {
|
||||
@@ -251,7 +276,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
.orElseThrow(
|
||||
() -> new BadRequestException(String.format("User %s doesn't exist", email)));
|
||||
|
||||
if (!userToUpdate.getUserRoles().getRegistrarRoles().containsKey(registrarId)) {
|
||||
if (verifyAccess && !userToUpdate.getUserRoles().getRegistrarRoles().containsKey(registrarId)) {
|
||||
setFailedResponse(
|
||||
String.format("Can't update user not associated with registrarId %s", registrarId),
|
||||
SC_FORBIDDEN);
|
||||
@@ -260,6 +285,36 @@ public class ConsoleUsersAction extends ConsoleApiAction {
|
||||
return true;
|
||||
}
|
||||
|
||||
private User updateUserRegistrarRoles(
|
||||
String email, String registrarId, RegistrarRole newRole, boolean isDelete) {
|
||||
User userToUpdate = tm().loadByKeyIfPresent(VKey.create(User.class, email)).get();
|
||||
Map<String, RegistrarRole> updatedRegistrarRoles;
|
||||
if (isDelete) {
|
||||
updatedRegistrarRoles =
|
||||
userToUpdate.getUserRoles().getRegistrarRoles().entrySet().stream()
|
||||
.filter(entry -> !Objects.equals(entry.getKey(), registrarId))
|
||||
.collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
} else {
|
||||
updatedRegistrarRoles =
|
||||
ImmutableMap.<String, RegistrarRole>builder()
|
||||
.putAll(userToUpdate.getUserRoles().getRegistrarRoles())
|
||||
.put(registrarId, newRole)
|
||||
.buildKeepingLast();
|
||||
}
|
||||
var updatedUser =
|
||||
userToUpdate
|
||||
.asBuilder()
|
||||
.setUserRoles(
|
||||
userToUpdate
|
||||
.getUserRoles()
|
||||
.asBuilder()
|
||||
.setRegistrarRoles(updatedRegistrarRoles)
|
||||
.build())
|
||||
.build();
|
||||
tm().put(updatedUser);
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
private ImmutableList<User> getAllRegistrarUsers(String registrarId) {
|
||||
return tm().transact(
|
||||
() ->
|
||||
|
||||
@@ -26,8 +26,9 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.ConsoleUpdateHistory;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarBase;
|
||||
@@ -62,7 +63,6 @@ public class RegistrarsAction extends ConsoleApiAction {
|
||||
WHERE registrar_id in :registrarIds
|
||||
""";
|
||||
static final String PATH = "/console-api/registrars";
|
||||
private final Gson gson;
|
||||
private final Optional<Registrar> registrar;
|
||||
private final StringGenerator passwordGenerator;
|
||||
private final StringGenerator passcodeGenerator;
|
||||
@@ -70,12 +70,10 @@ public class RegistrarsAction extends ConsoleApiAction {
|
||||
@Inject
|
||||
public RegistrarsAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
Gson gson,
|
||||
@Parameter("registrar") Optional<Registrar> registrar,
|
||||
@Named("base58StringGenerator") StringGenerator passwordGenerator,
|
||||
@Named("digitOnlyStringGenerator") StringGenerator passcodeGenerator) {
|
||||
super(consoleApiParams);
|
||||
this.gson = gson;
|
||||
this.registrar = registrar;
|
||||
this.passcodeGenerator = passcodeGenerator;
|
||||
this.passwordGenerator = passwordGenerator;
|
||||
@@ -88,7 +86,7 @@ public class RegistrarsAction extends ConsoleApiAction {
|
||||
Streams.stream(Registrar.loadAll())
|
||||
.filter(r -> allowedRegistrarTypes.contains(r.getType()))
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
consoleApiParams.response().setPayload(gson.toJson(registrars));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(registrars));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
} else if (user.getUserRoles().getRegistrarRoles().values().stream()
|
||||
.anyMatch(role -> role.hasPermission(ConsolePermission.VIEW_REGISTRAR_DETAILS))) {
|
||||
@@ -106,7 +104,7 @@ public class RegistrarsAction extends ConsoleApiAction {
|
||||
.setParameter("registrarIds", accessibleRegistrarIds)
|
||||
.getResultList());
|
||||
|
||||
consoleApiParams.response().setPayload(gson.toJson(registrars));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(registrars));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
} else {
|
||||
consoleApiParams.response().setStatus(SC_FORBIDDEN);
|
||||
@@ -175,6 +173,11 @@ public class RegistrarsAction extends ConsoleApiAction {
|
||||
"Registrar with registrarId %s already exists",
|
||||
registrar.getRegistrarId());
|
||||
tm().putAll(registrar, contact);
|
||||
finishAndPersistConsoleUpdateHistory(
|
||||
new RegistrarUpdateHistory.Builder()
|
||||
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
|
||||
.setRegistrar(registrar)
|
||||
.setRequestBody(consoleApiParams.gson().toJson(registrar)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
@@ -60,18 +59,15 @@ import javax.inject.Inject;
|
||||
public class ContactAction extends ConsoleApiAction {
|
||||
static final String PATH = "/console-api/settings/contacts";
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private final Gson gson;
|
||||
private final Optional<ImmutableSet<RegistrarPoc>> contacts;
|
||||
private final String registrarId;
|
||||
|
||||
@Inject
|
||||
public ContactAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
Gson gson,
|
||||
@Parameter("registrarId") String registrarId,
|
||||
@Parameter("contacts") Optional<ImmutableSet<RegistrarPoc>> contacts) {
|
||||
super(consoleApiParams);
|
||||
this.gson = gson;
|
||||
this.registrarId = registrarId;
|
||||
this.contacts = contacts;
|
||||
}
|
||||
@@ -90,7 +86,7 @@ public class ContactAction extends ConsoleApiAction {
|
||||
.collect(toImmutableList()));
|
||||
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
consoleApiParams.response().setPayload(gson.toJson(am));
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(am));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,6 +25,8 @@ import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
import google.registry.flows.certs.CertificateChecker.InsecureCertificateException;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.ConsoleUpdateHistory;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
@@ -117,6 +119,11 @@ public class SecurityAction extends ConsoleApiAction {
|
||||
|
||||
Registrar updatedRegistrar = updatedRegistrarBuilder.build();
|
||||
tm().put(updatedRegistrar);
|
||||
finishAndPersistConsoleUpdateHistory(
|
||||
new RegistrarUpdateHistory.Builder()
|
||||
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
|
||||
.setRegistrar(updatedRegistrar)
|
||||
.setRequestBody(consoleApiParams.gson().toJson(registrar.get())));
|
||||
|
||||
sendExternalUpdatesIfNecessary(
|
||||
EmailInfo.create(savedRegistrar, updatedRegistrar, ImmutableSet.of(), ImmutableSet.of()));
|
||||
|
||||
@@ -22,6 +22,8 @@ import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.ConsoleUpdateHistory;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
@@ -104,6 +106,11 @@ public class WhoisRegistrarFieldsAction extends ConsoleApiAction {
|
||||
.setEmailAddress(providedRegistrar.getEmailAddress())
|
||||
.build();
|
||||
tm().put(newRegistrar);
|
||||
finishAndPersistConsoleUpdateHistory(
|
||||
new RegistrarUpdateHistory.Builder()
|
||||
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
|
||||
.setRegistrar(newRegistrar)
|
||||
.setRequestBody(consoleApiParams.gson().toJson(registrar.get())));
|
||||
sendExternalUpdatesIfNecessary(
|
||||
EmailInfo.create(
|
||||
savedRegistrar,
|
||||
|
||||
@@ -121,7 +121,7 @@ class ExtensionManagerTest {
|
||||
void testMetadataExtension_forbiddenWhenNotToolSource() {
|
||||
ExtensionManager manager =
|
||||
new TestInstanceBuilder()
|
||||
.setEppRequestSource(EppRequestSource.CONSOLE)
|
||||
.setEppRequestSource(EppRequestSource.TLS)
|
||||
.setDeclaredUris()
|
||||
.setSuppliedExtensions(MetadataExtension.class)
|
||||
.build();
|
||||
|
||||
@@ -1247,4 +1247,15 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile("domain_delete_response_fee_free_grace.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_skipsPollMessage_whenConfigured() throws Exception {
|
||||
setUpSuccessfulTest();
|
||||
domain =
|
||||
persistResource(
|
||||
domain.asBuilder().setPersistedCurrentSponsorRegistrarId("NewRegistrar").build());
|
||||
setRegistrarIdForFlow("NewRegistrar");
|
||||
runFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
|
||||
assertPollMessages();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ import google.registry.model.reporting.DomainTransactionRecord;
|
||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -103,12 +104,12 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
|
||||
setEppInput("domain_update_restore_request.xml", ImmutableMap.of("DOMAIN", "example.tld"));
|
||||
}
|
||||
|
||||
void persistPendingDeleteDomain() throws Exception {
|
||||
Domain persistPendingDeleteDomain() throws Exception {
|
||||
// The domain is now past what had been its expiration date at the time of deletion.
|
||||
persistPendingDeleteDomain(clock.nowUtc().minusDays(5));
|
||||
return persistPendingDeleteDomain(clock.nowUtc().minusDays(5));
|
||||
}
|
||||
|
||||
void persistPendingDeleteDomain(DateTime expirationTime) throws Exception {
|
||||
Domain persistPendingDeleteDomain(DateTime expirationTime) throws Exception {
|
||||
Domain domain = persistResource(DatabaseHelper.newDomain(getUniqueIdFromCommand()));
|
||||
HistoryEntry historyEntry =
|
||||
persistResource(
|
||||
@@ -118,29 +119,31 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
|
||||
.setRegistrarId(domain.getCurrentSponsorRegistrarId())
|
||||
.setDomain(domain)
|
||||
.build());
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setRegistrationExpirationTime(expirationTime)
|
||||
.setDeletionTime(clock.nowUtc().plusDays(35))
|
||||
.addGracePeriod(
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.REDEMPTION,
|
||||
domain.getRepoId(),
|
||||
clock.nowUtc().plusDays(1),
|
||||
"TheRegistrar",
|
||||
null))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.setDeletePollMessage(
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(clock.nowUtc().plusDays(5))
|
||||
.setHistoryEntry(historyEntry)
|
||||
.build())
|
||||
.createVKey())
|
||||
.build());
|
||||
domain =
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setRegistrationExpirationTime(expirationTime)
|
||||
.setDeletionTime(clock.nowUtc().plusDays(35))
|
||||
.addGracePeriod(
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.REDEMPTION,
|
||||
domain.getRepoId(),
|
||||
clock.nowUtc().plusDays(1),
|
||||
"TheRegistrar",
|
||||
null))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.setDeletePollMessage(
|
||||
persistResource(
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(clock.nowUtc().plusDays(5))
|
||||
.setHistoryEntry(historyEntry)
|
||||
.build())
|
||||
.createVKey())
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
return domain;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -491,6 +494,15 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
|
||||
loadFile("domain_update_restore_request_response_premium.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_worksWithoutPollMessage() throws Exception {
|
||||
Domain domain = persistPendingDeleteDomain();
|
||||
VKey<PollMessage.OneTime> deletePollMessage = domain.getDeletePollMessage();
|
||||
persistResource(domain.asBuilder().setDeletePollMessage(null).build());
|
||||
DatabaseHelper.deleteByKey(deletePollMessage);
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_doesNotExist() throws Exception {
|
||||
ResourceDoesNotExistException thrown =
|
||||
|
||||
@@ -20,6 +20,7 @@ import static org.mockito.Mockito.when;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.groups.GmailClient;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.request.RequestModule;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.ui.server.SendEmailUtils;
|
||||
@@ -45,7 +46,13 @@ public final class ConsoleApiParamsUtils {
|
||||
xsrfTokenManager.generateToken(
|
||||
authResult.user().map(User::getEmailAddress).orElse("")))
|
||||
});
|
||||
when(request.getRequestURI()).thenReturn("/console/fake-url");
|
||||
return ConsoleApiParams.create(
|
||||
request, new FakeResponse(), authResult, sendEmailUtils, xsrfTokenManager);
|
||||
request,
|
||||
new FakeResponse(),
|
||||
authResult,
|
||||
sendEmailUtils,
|
||||
xsrfTokenManager,
|
||||
RequestModule.provideGson());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1168,6 +1168,10 @@ public final class DatabaseHelper {
|
||||
tm().transact(() -> tm().delete(resource));
|
||||
}
|
||||
|
||||
public static void deleteByKey(VKey<?> key) {
|
||||
tm().transact(() -> tm().delete(key));
|
||||
}
|
||||
|
||||
/** Force the create and update timestamps to get written into the resource. */
|
||||
public static <R> R cloneAndSetAutoTimestamps(final R resource) {
|
||||
// We have to separate the read and write operation into different transactions otherwise JPA
|
||||
@@ -1294,6 +1298,11 @@ public final class DatabaseHelper {
|
||||
return tm().transact(() -> tm().loadByEntitiesIfPresent(entities));
|
||||
}
|
||||
|
||||
/** Loads the only instance of this particular class, or empty if none exists. */
|
||||
public static <T> Optional<T> loadSingleton(Class<T> clazz) {
|
||||
return tm().transact(() -> tm().loadSingleton(clazz));
|
||||
}
|
||||
|
||||
/** Returns whether or not the given entity exists in Cloud SQL. */
|
||||
public static boolean existsInDb(ImmutableObject object) {
|
||||
return tm().transact(() -> tm().exists(object));
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
// Copyright 2024 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.ui.server.console;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.loadByEntity;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.flows.DaggerEppTestComponent;
|
||||
import google.registry.flows.EppController;
|
||||
import google.registry.flows.EppTestComponent;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Tests for {@link ConsoleBulkDomainAction}. */
|
||||
public class ConsoleBulkDomainActionTest {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2024-05-13T00:00:00.000Z"));
|
||||
|
||||
@RegisterExtension
|
||||
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
private EppController eppController;
|
||||
private FakeResponse fakeResponse;
|
||||
private Domain domain;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
persistResource(
|
||||
new FeatureFlag()
|
||||
.asBuilder()
|
||||
.setFeatureName(MINIMUM_DATASET_CONTACTS_OPTIONAL)
|
||||
.setStatusMap(ImmutableSortedMap.of(START_OF_TIME, INACTIVE))
|
||||
.build());
|
||||
eppController =
|
||||
DaggerEppTestComponent.builder()
|
||||
.fakesAndMocksModule(EppTestComponent.FakesAndMocksModule.create(clock))
|
||||
.build()
|
||||
.startRequest()
|
||||
.eppController();
|
||||
createTld("tld");
|
||||
domain =
|
||||
persistDomainWithDependentResources(
|
||||
"example",
|
||||
"tld",
|
||||
persistActiveContact("contact1234"),
|
||||
clock.nowUtc(),
|
||||
clock.nowUtc().minusMonths(1),
|
||||
clock.nowUtc().plusMonths(11));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_delete() {
|
||||
ConsoleBulkDomainAction action =
|
||||
createAction(
|
||||
"DELETE",
|
||||
GSON.toJsonTree(
|
||||
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")));
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(fakeResponse.getPayload())
|
||||
.isEqualTo(
|
||||
"{\"example.tld\":{\"message\":\"Command completed"
|
||||
+ " successfully\",\"responseCode\":1000}}");
|
||||
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_suspend() throws Exception {
|
||||
User adminUser =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("email@email.com")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).setIsAdmin(true).build())
|
||||
.build());
|
||||
ConsoleBulkDomainAction action =
|
||||
createAction(
|
||||
"SUSPEND",
|
||||
GSON.toJsonTree(
|
||||
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")),
|
||||
adminUser);
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(fakeResponse.getPayload())
|
||||
.isEqualTo(
|
||||
"{\"example.tld\":{\"message\":\"Command completed"
|
||||
+ " successfully\",\"responseCode\":1000}}");
|
||||
assertThat(loadByEntity(domain).getStatusValues())
|
||||
.containsAtLeast(
|
||||
StatusValue.SERVER_RENEW_PROHIBITED,
|
||||
StatusValue.SERVER_TRANSFER_PROHIBITED,
|
||||
StatusValue.SERVER_UPDATE_PROHIBITED,
|
||||
StatusValue.SERVER_DELETE_PROHIBITED,
|
||||
StatusValue.SERVER_HOLD);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHalfSuccess_halfNonexistent() throws Exception {
|
||||
ConsoleBulkDomainAction action =
|
||||
createAction(
|
||||
"DELETE",
|
||||
GSON.toJsonTree(
|
||||
ImmutableMap.of(
|
||||
"domainList",
|
||||
ImmutableList.of("example.tld", "nonexistent.tld"),
|
||||
"reason",
|
||||
"test")));
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(fakeResponse.getPayload())
|
||||
.isEqualTo(
|
||||
"{\"example.tld\":{\"message\":\"Command completed"
|
||||
+ " successfully\",\"responseCode\":1000},\"nonexistent.tld\":{\"message\":\"The"
|
||||
+ " domain with given ID (nonexistent.tld) doesn\\u0027t"
|
||||
+ " exist.\",\"responseCode\":2303}}");
|
||||
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_badActionString() {
|
||||
ConsoleBulkDomainAction action = createAction("bad", null);
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_BAD_REQUEST);
|
||||
assertThat(fakeResponse.getPayload())
|
||||
.isEqualTo(
|
||||
"No enum constant"
|
||||
+ " google.registry.ui.server.console.ConsoleBulkDomainAction.BulkAction.bad");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_emptyBody() {
|
||||
ConsoleBulkDomainAction action = createAction("DELETE", null);
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_BAD_REQUEST);
|
||||
assertThat(fakeResponse.getPayload()).isEqualTo("Bulk action payload must be present");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_noPermission() {
|
||||
JsonElement payload =
|
||||
GSON.toJsonTree(ImmutableMap.of("domainList", ImmutableList.of("domain.tld")));
|
||||
ConsoleBulkDomainAction action =
|
||||
createAction(
|
||||
"DELETE",
|
||||
payload,
|
||||
new User.Builder()
|
||||
.setEmailAddress("foobar@theregistrar.com")
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder()
|
||||
.setRegistrarRoles(
|
||||
ImmutableMap.of("TheRegistrar", RegistrarRole.ACCOUNT_MANAGER))
|
||||
.build())
|
||||
.build());
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_suspend_nonAdmin() {
|
||||
ConsoleBulkDomainAction action =
|
||||
createAction(
|
||||
"SUSPEND",
|
||||
GSON.toJsonTree(
|
||||
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")));
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
|
||||
Map<String, ConsoleBulkDomainAction.ConsoleEppOutput> payload =
|
||||
GSON.fromJson(fakeResponse.getPayload(), new TypeToken<>() {});
|
||||
assertThat(payload).containsKey("example.tld");
|
||||
assertThat(payload.get("example.tld").responseCode()).isEqualTo(2004);
|
||||
assertThat(payload.get("example.tld").message()).contains("cannot be set by clients");
|
||||
assertThat(loadByEntity(domain)).isEqualTo(domain);
|
||||
}
|
||||
|
||||
private ConsoleBulkDomainAction createAction(String action, JsonElement payload) {
|
||||
User user =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("email@email.com")
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build());
|
||||
return createAction(action, payload, user);
|
||||
}
|
||||
|
||||
private ConsoleBulkDomainAction createAction(String action, JsonElement payload, User user) {
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
ConsoleApiParams params = ConsoleApiParamsUtils.createFake(authResult);
|
||||
when(params.request().getMethod()).thenReturn("POST");
|
||||
fakeResponse = (FakeResponse) params.response();
|
||||
return new ConsoleBulkDomainAction(
|
||||
params, eppController, "TheRegistrar", action, Optional.ofNullable(payload));
|
||||
}
|
||||
}
|
||||
@@ -22,13 +22,11 @@ import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.RequestModule;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
@@ -40,7 +38,6 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
/** Tests for {@link google.registry.ui.server.console.ConsoleDomainGetAction}. */
|
||||
public class ConsoleDomainGetActionTest {
|
||||
|
||||
private static final Gson GSON = RequestModule.provideGson();
|
||||
private ConsoleApiParams consoleApiParams;
|
||||
|
||||
@RegisterExtension
|
||||
@@ -124,6 +121,6 @@ public class ConsoleDomainGetActionTest {
|
||||
private ConsoleDomainGetAction createAction(AuthResult authResult, String domain) {
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.GET.toString());
|
||||
return new ConsoleDomainGetAction(consoleApiParams, GSON, domain);
|
||||
return new ConsoleDomainGetAction(consoleApiParams, domain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +264,6 @@ public class ConsoleDomainListActionTest {
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(Action.Method.GET.toString());
|
||||
return new ConsoleDomainListAction(
|
||||
consoleApiParams,
|
||||
GSON,
|
||||
registrarId,
|
||||
Optional.ofNullable(checkpointTime),
|
||||
Optional.ofNullable(pageNumber),
|
||||
|
||||
@@ -21,7 +21,6 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
@@ -32,7 +31,6 @@ import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import java.io.IOException;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -41,8 +39,6 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class ConsoleDumDownloadActionTest {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2024-04-15T00:00:00.000Z"));
|
||||
|
||||
private ConsoleApiParams consoleApiParams;
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.ui.server.console;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
|
||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.loadSingleton;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
@@ -32,6 +33,7 @@ import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
@@ -41,6 +43,7 @@ import google.registry.request.RequestModule;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.ui.server.console.ConsoleEppPasswordAction.EppPasswordData;
|
||||
@@ -139,6 +142,10 @@ class ConsoleEppPasswordActionTest {
|
||||
() -> {
|
||||
credentials.validate(loadRegistrar("TheRegistrar"), "randomPassword");
|
||||
});
|
||||
assertThat(loadSingleton(RegistrarUpdateHistory.class).get().getRequestBody())
|
||||
.isEqualTo(
|
||||
"{\"registrarId\":\"TheRegistrar\",\"oldPassword\":\"********\",\"newPassword\":"
|
||||
+ "\"••••••••\",\"newPasswordRepeat\":\"••••••••\"}");
|
||||
}
|
||||
|
||||
private ConsoleEppPasswordAction createAction(
|
||||
@@ -150,6 +157,7 @@ class ConsoleEppPasswordActionTest {
|
||||
.setEmailAddress("email@email.com")
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
DatabaseHelper.putInDb(user);
|
||||
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
|
||||
@@ -245,7 +245,6 @@ class ConsoleOteActionTest {
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
|
||||
return new ConsoleOteAction(
|
||||
consoleApiParams,
|
||||
GSON,
|
||||
iamClient,
|
||||
registrarId,
|
||||
maybeGroupEmailAddress,
|
||||
|
||||
@@ -34,7 +34,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.groups.GmailClient;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
@@ -44,7 +43,6 @@ import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.RegistryLock;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.RequestModule;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
@@ -83,8 +81,6 @@ public class ConsoleRegistryLockActionTest {
|
||||
https://registrarconsole.tld/console/#/registry-lock-verify?lockVerificationCode=\
|
||||
123456789ABCDEFGHJKLMNPQRSTUVWXY""";
|
||||
|
||||
private static final Gson GSON = RequestModule.provideGson();
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock(DateTime.parse("2024-04-18T12:00:00.000Z"));
|
||||
|
||||
@RegisterExtension
|
||||
@@ -128,10 +124,10 @@ public class ConsoleRegistryLockActionTest {
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(
|
||||
"""
|
||||
[{"domainName":"example.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-18T12:00:00.000Z"},"unlockRequestTime":"null","lockCompletionTime":\
|
||||
"2024-04-18T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false}]\
|
||||
""");
|
||||
[{"domainName":"example.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-18T12:00:00.000Z"},"unlockRequestTime":"null","lockCompletionTime":\
|
||||
"2024-04-18T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false}]\
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -222,25 +218,25 @@ public class ConsoleRegistryLockActionTest {
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(
|
||||
"""
|
||||
[{"domainName":"adminexample.test","lockRequestTime":{"creationTime":"2024-04-19T12:00:00.001Z"},\
|
||||
"unlockRequestTime":"null","lockCompletionTime":"2024-04-19T12:00:00.001Z","unlockCompletionTime":\
|
||||
"null","isSuperuser":true},\
|
||||
\
|
||||
{"domainName":"example.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":\
|
||||
"2024-04-19T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
|
||||
\
|
||||
{"domainName":"expiredunlock.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-18T12:00:00.000Z"},"unlockRequestTime":"2024-04-18T12:00:00.000Z",\
|
||||
"lockCompletionTime":"2024-04-18T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
|
||||
\
|
||||
{"domainName":"incompleteunlock.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"2024-04-19T12:00:00.001Z",\
|
||||
"lockCompletionTime":"2024-04-19T12:00:00.001Z","unlockCompletionTime":"null","isSuperuser":false},\
|
||||
\
|
||||
{"domainName":"pending.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":"null",\
|
||||
"unlockCompletionTime":"null","isSuperuser":false}]""");
|
||||
[{"domainName":"adminexample.test","lockRequestTime":{"creationTime":"2024-04-19T12:00:00.001Z"},\
|
||||
"unlockRequestTime":"null","lockCompletionTime":"2024-04-19T12:00:00.001Z","unlockCompletionTime":\
|
||||
"null","isSuperuser":true},\
|
||||
\
|
||||
{"domainName":"example.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":\
|
||||
"2024-04-19T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
|
||||
\
|
||||
{"domainName":"expiredunlock.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-18T12:00:00.000Z"},"unlockRequestTime":"2024-04-18T12:00:00.000Z",\
|
||||
"lockCompletionTime":"2024-04-18T12:00:00.000Z","unlockCompletionTime":"null","isSuperuser":false},\
|
||||
\
|
||||
{"domainName":"incompleteunlock.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"2024-04-19T12:00:00.001Z",\
|
||||
"lockCompletionTime":"2024-04-19T12:00:00.001Z","unlockCompletionTime":"null","isSuperuser":false},\
|
||||
\
|
||||
{"domainName":"pending.test","registrarPocId":"johndoe@theregistrar.com","lockRequestTime":\
|
||||
{"creationTime":"2024-04-19T12:00:00.001Z"},"unlockRequestTime":"null","lockCompletionTime":"null",\
|
||||
"unlockCompletionTime":"null","isSuperuser":false}]""");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -508,7 +504,7 @@ public class ConsoleRegistryLockActionTest {
|
||||
new CloudTasksHelper(fakeClock).getTestCloudTasksUtils());
|
||||
response = (FakeResponse) params.response();
|
||||
return new ConsoleRegistryLockAction(
|
||||
params, domainLockUtils, gmailClient, GSON, optionalPostInput, "TheRegistrar");
|
||||
params, domainLockUtils, gmailClient, optionalPostInput, "TheRegistrar");
|
||||
}
|
||||
|
||||
private ConsoleApiParams createParams() {
|
||||
|
||||
@@ -24,7 +24,6 @@ import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STAT
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
@@ -32,7 +31,6 @@ import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.RegistryLock;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.RequestModule;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
@@ -51,7 +49,6 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public class ConsoleRegistryLockVerifyActionTest {
|
||||
|
||||
private static final String DEFAULT_CODE = "123456789ABCDEFGHJKLMNPQRSTUUUUU";
|
||||
private static final Gson GSON = RequestModule.provideGson();
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@RegisterExtension
|
||||
@@ -214,6 +211,6 @@ public class ConsoleRegistryLockVerifyActionTest {
|
||||
"adminreg",
|
||||
new CloudTasksHelper(fakeClock).getTestCloudTasksUtils());
|
||||
response = (FakeResponse) params.response();
|
||||
return new ConsoleRegistryLockVerifyAction(params, domainLockUtils, GSON, verificationCode);
|
||||
return new ConsoleRegistryLockVerifyAction(params, domainLockUtils, verificationCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.model.registrar.RegistrarPocBase.Type.WHOIS;
|
||||
import static google.registry.testing.DatabaseHelper.createTlds;
|
||||
import static google.registry.testing.DatabaseHelper.loadSingleton;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
@@ -29,6 +31,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
@@ -85,10 +88,11 @@ class ConsoleUpdateRegistrarActionTest {
|
||||
.setRegistryLockAllowed(false)
|
||||
.build());
|
||||
user =
|
||||
new User.Builder()
|
||||
.setEmailAddress("user@registrarId.com")
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("user@registrarId.com")
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build());
|
||||
consoleApiParams = createParams();
|
||||
}
|
||||
|
||||
@@ -104,6 +108,9 @@ class ConsoleUpdateRegistrarActionTest {
|
||||
assertThat(newRegistrar.getAllowedTlds()).containsExactly("app", "dev");
|
||||
assertThat(newRegistrar.isRegistryLockAllowed()).isFalse();
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
|
||||
assertAboutImmutableObjects()
|
||||
.that(newRegistrar)
|
||||
.hasFieldsEqualTo(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -20,6 +20,7 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
@@ -71,6 +72,8 @@ class ConsoleUserDataActionTest {
|
||||
GSON.fromJson(((FakeResponse) consoleApiParams.response()).getPayload(), Map.class);
|
||||
assertThat(jsonObject)
|
||||
.containsExactly(
|
||||
"userRoles",
|
||||
ImmutableMap.of(),
|
||||
"isAdmin",
|
||||
true,
|
||||
"technicalDocsUrl",
|
||||
|
||||
@@ -246,6 +246,50 @@ class ConsoleUsersActionTest {
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_removesRole() throws IOException {
|
||||
User user1 = DatabaseHelper.loadByKey(VKey.create(User.class, "test1@test.com"));
|
||||
AuthResult authResult =
|
||||
AuthResult.createUser(
|
||||
user1
|
||||
.asBuilder()
|
||||
.setUserRoles(user1.getUserRoles().asBuilder().setIsAdmin(true).build())
|
||||
.build());
|
||||
DatabaseHelper.persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("test4@test.com")
|
||||
.setUserRoles(
|
||||
new UserRoles()
|
||||
.asBuilder()
|
||||
.setRegistrarRoles(
|
||||
ImmutableMap.of(
|
||||
"TheRegistrar",
|
||||
RegistrarRole.PRIMARY_CONTACT,
|
||||
"SomeRegistrar",
|
||||
RegistrarRole.PRIMARY_CONTACT))
|
||||
.build())
|
||||
.build());
|
||||
|
||||
ConsoleUsersAction action =
|
||||
createAction(
|
||||
Optional.of(ConsoleApiParamsUtils.createFake(authResult)),
|
||||
Optional.of("DELETE"),
|
||||
Optional.of(
|
||||
new UserData("test4@test.com", RegistrarRole.ACCOUNT_MANAGER.toString(), null)));
|
||||
|
||||
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
when(directory.users()).thenReturn(users);
|
||||
when(users.delete(any(String.class))).thenReturn(delete);
|
||||
action.run();
|
||||
var response = ((FakeResponse) consoleApiParams.response());
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
Optional<User> actualUser =
|
||||
DatabaseHelper.loadByKeyIfPresent(VKey.create(User.class, "test4@test.com"));
|
||||
assertThat(actualUser).isPresent();
|
||||
assertThat(actualUser.get().getUserRoles().getRegistrarRoles().containsKey("TheRegistrar"))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_limitedTo4UsersPerRegistrar() throws IOException {
|
||||
User user1 = DatabaseHelper.loadByKey(VKey.create(User.class, "test1@test.com"));
|
||||
@@ -352,7 +396,6 @@ class ConsoleUsersActionTest {
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(method.orElse("GET"));
|
||||
return new ConsoleUsersAction(
|
||||
consoleApiParams,
|
||||
GSON,
|
||||
directory,
|
||||
iamClient,
|
||||
"email.com",
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.testing.DatabaseHelper.loadAllOf;
|
||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.loadSingleton;
|
||||
import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||
@@ -30,6 +32,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
@@ -183,6 +186,9 @@ class RegistrarsActionTest {
|
||||
.findAny()
|
||||
.isPresent())
|
||||
.isTrue();
|
||||
assertAboutImmutableObjects()
|
||||
.that(r)
|
||||
.isEqualExceptFields(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -225,10 +231,8 @@ class RegistrarsActionTest {
|
||||
}
|
||||
|
||||
private User createUser(UserRoles userRoles) {
|
||||
return new User.Builder()
|
||||
.setEmailAddress("email@email.com")
|
||||
.setUserRoles(userRoles)
|
||||
.build();
|
||||
return persistResource(
|
||||
new User.Builder().setEmailAddress("email@email.com").setUserRoles(userRoles).build());
|
||||
}
|
||||
|
||||
private RegistrarsAction createAction(Action.Method method, AuthResult authResult) {
|
||||
@@ -236,7 +240,7 @@ class RegistrarsActionTest {
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
|
||||
if (method.equals(Action.Method.GET)) {
|
||||
return new RegistrarsAction(
|
||||
consoleApiParams, GSON, Optional.ofNullable(null), passwordGenerator, passcodeGenerator);
|
||||
consoleApiParams, Optional.ofNullable(null), passwordGenerator, passcodeGenerator);
|
||||
} else {
|
||||
try {
|
||||
doReturn(new BufferedReader(new StringReader(registrarParamMap.toString())))
|
||||
@@ -245,7 +249,6 @@ class RegistrarsActionTest {
|
||||
} catch (IOException e) {
|
||||
return new RegistrarsAction(
|
||||
consoleApiParams,
|
||||
GSON,
|
||||
Optional.ofNullable(null),
|
||||
passwordGenerator,
|
||||
passcodeGenerator);
|
||||
@@ -254,7 +257,7 @@ class RegistrarsActionTest {
|
||||
ConsoleModule.provideRegistrar(
|
||||
GSON, RequestModule.provideJsonBody(consoleApiParams.request(), GSON));
|
||||
return new RegistrarsAction(
|
||||
consoleApiParams, GSON, maybeRegistrar, passwordGenerator, passcodeGenerator);
|
||||
consoleApiParams, maybeRegistrar, passwordGenerator, passcodeGenerator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,10 +480,10 @@ class ContactActionTest {
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
|
||||
if (method.equals(Action.Method.GET)) {
|
||||
return new ContactAction(consoleApiParams, GSON, registrarId, Optional.empty());
|
||||
return new ContactAction(consoleApiParams, registrarId, Optional.empty());
|
||||
} else {
|
||||
return new ContactAction(
|
||||
consoleApiParams, GSON, registrarId, Optional.of(ImmutableSet.copyOf(contacts)));
|
||||
consoleApiParams, registrarId, Optional.of(ImmutableSet.copyOf(contacts)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
package google.registry.ui.server.console.settings;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT2;
|
||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.loadSingleton;
|
||||
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
@@ -28,6 +30,7 @@ import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.flows.certs.CertificateChecker;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.Action;
|
||||
@@ -98,6 +101,9 @@ class SecurityActionTest {
|
||||
.isEqualTo("GNd6ZP8/n91t9UTnpxR8aH7aAW4+CpvufYx9ViGbcMY");
|
||||
assertThat(r.getIpAddressAllowList().get(0).getIp()).isEqualTo("192.168.1.1");
|
||||
assertThat(r.getIpAddressAllowList().get(0).getNetmask()).isEqualTo(32);
|
||||
assertAboutImmutableObjects()
|
||||
.that(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar())
|
||||
.hasFieldsEqualTo(r);
|
||||
}
|
||||
|
||||
private SecurityAction createAction(AuthResult authResult, String registrarId)
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.ui.server.console.settings;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
|
||||
import static google.registry.testing.DatabaseHelper.loadSingleton;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
@@ -27,6 +28,7 @@ import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.console.RegistrarRole;
|
||||
import google.registry.model.console.RegistrarUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
@@ -129,6 +131,9 @@ public class WhoisRegistrarFieldsActionTest {
|
||||
.that(newRegistrar)
|
||||
.isEqualExceptFields(
|
||||
oldRegistrar, "whoisServer", "url", "localizedAddress", "phoneNumber", "faxNumber");
|
||||
assertAboutImmutableObjects()
|
||||
.that(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar())
|
||||
.hasFieldsEqualTo(newRegistrar);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user