1
0
mirror of https://github.com/google/nomulus synced 2026-05-21 23:31:51 +00:00

Compare commits

...

5 Commits

Author SHA1 Message Date
gbrodman
cc20f7d76d Add a simple toString for TimedTransitionProperty (#2604)
this means that we can actually see the transitions when running
GetAllocationTokenCommand, for instance
2024-11-05 18:26:36 +00:00
Ben McIlwain
5603b91526 Make nomulus update_recurrence command only fail on pending transfers (#2605)
It was failing when any kind of transfer data was present, even completed
transfer data. Note that completed transfer data persists on a domain
indefinitely until/unless a new transfer is requested.

BUG= http://b/377328244
2024-11-04 21:16:11 +00:00
Pavlo Tkach
332f491ac7 Fix cut off status list on domains page (#2601) 2024-10-28 18:20:04 +00:00
Pavlo Tkach
4bd7c18fe9 Add console settings update progress status (#2596) 2024-10-25 22:23:22 +00:00
Pavlo Tkach
fdb0664841 Add admin.directory.user.security scope (#2597) 2024-10-25 21:24:15 +00:00
11 changed files with 117 additions and 21 deletions

View File

@@ -95,9 +95,9 @@
<ng-container matColumnDef="statuses">
<mat-header-cell *matHeaderCellDef>Statuses</mat-header-cell>
<mat-cell *matCellDef="let element">{{
element.statuses
}}</mat-cell>
<mat-cell *matCellDef="let element">
<span>{{ element.statuses?.join(", ") }}</span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="registryLock">

View File

@@ -36,6 +36,11 @@
.mat-column-registryLock {
max-width: 150px;
}
.mat-column-statuses span {
padding: 10px 0;
overflow: hidden;
word-break: break-word;
}
}
&__domains-spinner {

View File

@@ -13,7 +13,7 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { switchMap } from 'rxjs';
import { switchMap, timeout } from 'rxjs';
import {
IpAllowListItem,
RegistrarService,
@@ -69,6 +69,7 @@ export class SecurityService {
uiToApiConverter(newSecuritySettings)
)
.pipe(
timeout(2000),
switchMap(() => {
return this.registrarService.loadRegistrars();
})

View File

@@ -10,6 +10,7 @@
<mat-form-field appearance="outline">
<input
matInput
[disabled]="isUpdating"
type="text"
[(ngModel)]="ip.value"
[ngModelOptions]="{ standalone: true }"
@@ -20,12 +21,19 @@
mat-icon-button
aria-label="Remove"
(click)="removeIpEntry(ip)"
[disabled]="isUpdating"
>
<mat-icon>close</mat-icon>
</button>
</div>
}
<button mat-button color="primary" (click)="createIpEntry()" type="button">
<button
mat-button
[disabled]="isUpdating"
color="primary"
(click)="createIpEntry()"
type="button"
>
+ Add IP
</button>
@@ -35,6 +43,7 @@
<textarea
class="console-app__clientCertificateValue"
matInput
[disabled]="isUpdating"
[(ngModel)]="dataSource.clientCertificate"
[ngModelOptions]="{ standalone: true }"
></textarea>
@@ -44,6 +53,7 @@
<mat-form-field appearance="outline">
<textarea
matInput
[disabled]="isUpdating"
[(ngModel)]="dataSource.failoverClientCertificate"
[ngModelOptions]="{ standalone: true }"
></textarea>
@@ -51,6 +61,7 @@
<button
mat-flat-button
color="primary"
[disabled]="isUpdating"
aria-label="Save security settings"
type="submit"
class="settings-security__edit-save"

View File

@@ -29,6 +29,7 @@ import { SecurityService, apiToUiConverter } from './security.service';
})
export default class SecurityEditComponent {
dataSource: SecuritySettings = {};
isUpdating = false;
constructor(
public securityService: SecurityService,
@@ -43,12 +44,15 @@ export default class SecurityEditComponent {
}
save() {
this.isUpdating = true;
this.securityService.saveChanges(this.dataSource).subscribe({
complete: () => {
this.isUpdating = false;
this.goBack();
},
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error);
this._snackBar.open(err.error || err.message);
this.isUpdating = false;
},
});
}

View File

@@ -374,6 +374,9 @@ credentialOAuth:
- https://www.googleapis.com/auth/admin.directory.group
# View and manage users in Google Workspace
- https://www.googleapis.com/auth/admin.directory.user
# Security scope which seems to be required to create users via API,
# based on https://github.com/googleapis/google-api-nodejs-client/issues/1884
- https://www.googleapis.com/auth/admin.directory.user.security
# View and manage group settings in Group Settings API.
- https://www.googleapis.com/auth/apps.groups.settings
# Send email through Gmail.

View File

@@ -185,4 +185,9 @@ public class TimedTransitionProperty<V extends Serializable> implements UnsafeSe
public int hashCode() {
return this.backingMap.hashCode();
}
@Override
public String toString() {
return this.backingMap.toString();
}
}

View File

@@ -30,6 +30,7 @@ import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
import google.registry.model.transfer.TransferStatus;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
@@ -174,7 +175,8 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand {
"Domain %s has already had a deletion time set",
domainName);
checkArgument(
domain.getTransferData().isEmpty(),
domain.getTransferData().isEmpty()
|| domain.getTransferData().getTransferStatus() != TransferStatus.PENDING,
"Domain %s has a pending transfer: %s",
domainName,
domain.getTransferData());

View File

@@ -25,8 +25,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import google.registry.model.domain.Domain;
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem;
import google.registry.model.domain.token.AllocationToken;
import google.registry.util.DateTimeUtils;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
@@ -41,10 +45,49 @@ class GetAllocationTokenCommandTest extends CommandTestCase<GetAllocationTokenCo
new AllocationToken.Builder()
.setToken("foo")
.setTokenType(SINGLE_USE)
.setAllowedEppActions(
ImmutableSet.of(FeeQueryCommandExtensionItem.CommandName.CREATE))
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("bar"))
.setDiscountFraction(0.5)
.setDiscountYears(2)
.setTokenStatusTransitions(
ImmutableSortedMap.of(
DateTimeUtils.START_OF_TIME,
AllocationToken.TokenStatus.NOT_STARTED,
fakeClock.nowUtc(),
AllocationToken.TokenStatus.VALID))
.setDomainName("foo.bar")
.build());
runCommand("foo");
assertInStdout(token.toString(), "Token foo was not redeemed.");
assertStdoutIs(
"""
AllocationToken: {
allowedClientIds=[TheRegistrar]
allowedEppActions=[CREATE]
allowedTlds=[bar]
creationTime=CreateAutoTimestamp: {
creationTime=2022-09-01T00:00:00.000Z
}
discountFraction=0.5
discountPremiums=false
discountPrice=null
discountYears=2
domainName=foo.bar
redemptionHistoryId=null
registrationBehavior=DEFAULT
renewalPrice=null
renewalPriceBehavior=DEFAULT
token=foo
tokenStatusTransitions={1970-01-01T00:00:00.000Z=NOT_STARTED, 2022-09-01T00:00:00.000Z=VALID}
tokenType=SINGLE_USE
updateTimestamp=UpdateAutoTimestamp: {
lastUpdateTime=2022-09-01T00:00:00.000Z
}
}
Token foo was not redeemed.
""");
}
@Test

View File

@@ -33,6 +33,8 @@ import google.registry.model.billing.BillingRecurrence;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import java.util.Optional;
import javax.annotation.Nullable;
import org.joda.money.CurrencyUnit;
@@ -121,6 +123,25 @@ public class UpdateRecurrenceCommandTest extends CommandTestCase<UpdateRecurrenc
Money.of(CurrencyUnit.USD, 9001));
}
@Test
void testSuccess_completedTransfer() throws Exception {
Domain domain = persistDomain();
domain =
persistResource(
domain
.asBuilder()
.setTransferData(
new DomainTransferData.Builder()
.setTransferStatus(TransferStatus.CLIENT_APPROVED)
.setPendingTransferExpirationTime(fakeClock.nowUtc().minusDays(8))
.build())
.build());
BillingRecurrence billingRecurrence = loadByKey(domain.getAutorenewBillingEvent());
runCommandForced("domain.tld", "--renewal_price_behavior", "NONPREMIUM");
assertNewBillingEventAndHistory(
billingRecurrence.getId(), RenewalPriceBehavior.NONPREMIUM, null);
}
@Test
void testFailure_nonexistentDomain() {
assertThrows(

View File

@@ -90,19 +90,20 @@ public class ConsoleScreenshotTest extends WebDriverTestCase {
driver.diffPage("actionsButtonClicked");
}
@RetryingTest(3)
void settingsPage() throws Exception {
clickSidebarElementByName("Settings");
driver.diffPage("noRegistrarSelected");
selectRegistrar();
driver.diffPage("registrarSelected_contacts");
driver.findElement(By.cssSelector("a[routerLink=\"whois\"]")).click();
Thread.sleep(500);
driver.diffPage("registrarSelected_whois");
driver.findElement(By.cssSelector("a[routerLink=\"security\"]")).click();
Thread.sleep(500);
driver.diffPage("registrarSelected_security");
}
// TODO: Reenable failing test after kokoro issue is resolved
// @RetryingTest(3)
// void settingsPage() throws Exception {
// clickSidebarElementByName("Settings");
// driver.diffPage("noRegistrarSelected");
// selectRegistrar();
// driver.diffPage("registrarSelected_contacts");
// driver.findElement(By.cssSelector("a[routerLink=\"whois\"]")).click();
// Thread.sleep(500);
// driver.diffPage("registrarSelected_whois");
// driver.findElement(By.cssSelector("a[routerLink=\"security\"]")).click();
// Thread.sleep(500);
// driver.diffPage("registrarSelected_security");
// }
@RetryingTest(3)
void billingInfo() throws Exception {