Show pending locks in the locked-domains table (#495)

* Show pending locks in the locked-domains table

* asdf

* fix the tests

* including pending unlocks in the table

* fix the screenshot test
This commit is contained in:
gbrodman
2020-02-28 13:57:33 -05:00
committed by GitHub
parent 9283cd263f
commit e8ff4081a9
9 changed files with 152 additions and 54 deletions
@@ -25,11 +25,7 @@ import javax.persistence.EntityManager;
/** Data access object for {@link google.registry.schema.domain.RegistryLock}. */
public final class RegistryLockDao {
/**
* Returns the most recent version of the {@link RegistryLock} referred to by the verification
* code (there may be two instances of the same code in the database--one after lock object
* creation and one after verification.
*/
/** Returns the most recent version of the {@link RegistryLock} referred to by the code. */
public static Optional<RegistryLock> getByVerificationCode(String verificationCode) {
jpaTm().assertInTransaction();
EntityManager em = jpaTm().getEntityManager();
@@ -43,25 +39,24 @@ public final class RegistryLockDao {
return Optional.ofNullable(revisionId).map(revision -> em.find(RegistryLock.class, revision));
}
/** Returns all lock objects that this registrar has created. */
public static ImmutableList<RegistryLock> getLockedDomainsByRegistrarId(String registrarId) {
/** Returns all lock objects that this registrar has created, including pending locks. */
public static ImmutableList<RegistryLock> getLocksByRegistrarId(String registrarId) {
jpaTm().assertInTransaction();
return ImmutableList.copyOf(
jpaTm()
.getEntityManager()
.createQuery(
"SELECT lock FROM RegistryLock lock WHERE"
+ " lock.registrarId = :registrarId "
+ "AND lock.lockCompletionTimestamp IS NOT NULL "
+ "AND lock.unlockCompletionTimestamp IS NULL",
"SELECT lock FROM RegistryLock lock WHERE lock.registrarId = :registrarId"
+ " AND lock.unlockCompletionTimestamp IS NULL",
RegistryLock.class)
.setParameter("registrarId", registrarId)
.getResultList());
}
/**
* Returns the most recent lock object for a given domain specified by repo ID, or empty if this
* domain hasn't been locked before.
* Returns the most recent lock object for a given domain specified by repo ID.
*
* <p>Returns empty if this domain hasn't been locked before.
*/
public static Optional<RegistryLock> getMostRecentByRepoId(String repoId) {
jpaTm().assertInTransaction();
@@ -78,9 +73,10 @@ public final class RegistryLockDao {
}
/**
* Returns the most recent verified lock object for a given domain specified by repo ID, or empty
* if no lock has ever been finalized for this domain. This is different from {@link
* #getMostRecentByRepoId(String)} in that it only returns verified locks.
* Returns the most recent verified lock object for a given domain specified by repo ID.
*
* <p>Returns empty if no lock has ever been finalized for this domain. This is different from
* {@link #getMostRecentByRepoId(String)} in that it only returns verified locks.
*/
public static Optional<RegistryLock> getMostRecentVerifiedLockByRepoId(String repoId) {
jpaTm().assertInTransaction();
@@ -68,6 +68,8 @@ public final class RegistryLockGetAction implements JsonGetAction {
private static final String FULLY_QUALIFIED_DOMAIN_NAME_PARAM = "fullyQualifiedDomainName";
private static final String LOCKED_TIME_PARAM = "lockedTime";
private static final String LOCKED_BY_PARAM = "lockedBy";
private static final String IS_LOCK_PENDING_PARAM = "isLockPending";
private static final String IS_UNLOCK_PENDING_PARAM = "isUnlockPending";
private static final String USER_CAN_UNLOCK_PARAM = "userCanUnlock";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -155,20 +157,25 @@ public final class RegistryLockGetAction implements JsonGetAction {
return jpaTm()
.transact(
() ->
RegistryLockDao.getLockedDomainsByRegistrarId(clientId).stream()
RegistryLockDao.getLocksByRegistrarId(clientId).stream()
.filter(lock -> !lock.isLockRequestExpired(jpaTm().getTransactionTime()))
.filter(lock -> !lock.isUnlockRequestExpired(jpaTm().getTransactionTime()))
.map(lock -> lockToMap(lock, isAdmin))
.collect(toImmutableList()));
}
private ImmutableMap<String, ?> lockToMap(RegistryLock lock, boolean isAdmin) {
return ImmutableMap.of(
FULLY_QUALIFIED_DOMAIN_NAME_PARAM,
lock.getDomainName(),
LOCKED_TIME_PARAM,
lock.getLockCompletionTimestamp().map(DateTime::toString).orElse(""),
LOCKED_BY_PARAM,
lock.isSuperuser() ? "admin" : lock.getRegistrarPocId(),
USER_CAN_UNLOCK_PARAM,
isAdmin || !lock.isSuperuser());
return new ImmutableMap.Builder<String, Object>()
.put(FULLY_QUALIFIED_DOMAIN_NAME_PARAM, lock.getDomainName())
.put(
LOCKED_TIME_PARAM, lock.getLockCompletionTimestamp().map(DateTime::toString).orElse(""))
.put(LOCKED_BY_PARAM, lock.isSuperuser() ? "admin" : lock.getRegistrarPocId())
.put(IS_LOCK_PENDING_PARAM, !lock.getLockCompletionTimestamp().isPresent())
.put(
IS_UNLOCK_PENDING_PARAM,
lock.getUnlockRequestTimestamp().isPresent()
&& !lock.getUnlockCompletionTimestamp().isPresent())
.put(USER_CAN_UNLOCK_PARAM, isAdmin || !lock.isSuperuser())
.build();
}
}
@@ -37,7 +37,9 @@ registry.json.locks = {};
* fullyQualifiedDomainName: string,
* lockedTime: string,
* lockedBy: string,
* userCanUnlock: boolean
* userCanUnlock: boolean,
* isLockPending: boolean,
* isUnlockPending: boolean
* }}
*/
registry.json.locks.ExistingLock;
@@ -23,7 +23,8 @@
{template .locksContent}
{@param email: string}
{@param locks: list<[fullyQualifiedDomainName: string, lockedTime: string, lockedBy: string, userCanUnlock: bool]>}
{@param locks: list<[fullyQualifiedDomainName: string, lockedTime: string, lockedBy: string,
userCanUnlock: bool, isLockPending: bool, isUnlockPending: bool]>}
{@param lockEnabledForContact: bool}
{call .newLock}
@@ -63,7 +64,8 @@
/** Table that displays existing locks for this registrar. */
{template .existingLocksTable}
{@param locks: list<[fullyQualifiedDomainName: string, lockedTime: string, lockedBy: string, userCanUnlock: bool]>}
{@param locks: list<[fullyQualifiedDomainName: string, lockedTime: string, lockedBy: string,
userCanUnlock: bool, isLockPending: bool, isUnlockPending: bool]>}
{@param lockEnabledForContact: bool}
<h2>Existing locks</h2>
<br>
@@ -76,19 +78,24 @@
</tr>
{for $lock in $locks}
<tr class="{css('registry-locks-table-row')}">
<td>{$lock.fullyQualifiedDomainName}</td>
<td>{$lock.fullyQualifiedDomainName}
{if $lock.isLockPending}<i> (pending)</i>
{elseif $lock.isUnlockPending}<i> (unlock pending)</i>
{/if}</td>
<td>{$lock.lockedTime}</td>
<td>{$lock.lockedBy}</td>
<td>
<button id="button-unlock-{$lock.fullyQualifiedDomainName}"
{if $lockEnabledForContact and $lock.userCanUnlock}
class="domain-unlock-button {css('kd-button')} {css('kd-button-submit')}"
{else}
class="{css('kd-button')}"
disabled
{/if}
>Unlock
</button>
{if not $lock.isLockPending and not $lock.isUnlockPending}
<button id="button-unlock-{$lock.fullyQualifiedDomainName}"
{if $lockEnabledForContact and $lock.userCanUnlock}
class="domain-unlock-button {css('kd-button')} {css('kd-button-submit')}"
{else}
class="{css('kd-button')}"
disabled
{/if}
>Unlock
</button>
{/if}
</td>
</tr>
{/for}