Skip to content

Commit

Permalink
Allow list and Activation code updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Portals committed Sep 5, 2024
1 parent c1afbd5 commit 3123030
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 7 deletions.
2 changes: 2 additions & 0 deletions app/src/main/java/it/chalmers/gamma/GammaApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@SpringBootApplication
@ConfigurationPropertiesScan
public class GammaApplication {
Expand Down
40 changes: 40 additions & 0 deletions app/src/main/java/it/chalmers/gamma/ScheduledTasks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package it.chalmers.gamma;

import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository;
import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class ScheduledTasks {

private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class);

private final UserActivationRepository userActivationRepository;
private final PasswordResetRepository passwordResetRepository;

public ScheduledTasks(UserActivationRepository userActivationRepository, PasswordResetRepository passwordResetRepository) {
this.userActivationRepository = userActivationRepository;
this.passwordResetRepository = passwordResetRepository;
}

@Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15)
public void clearInvalidActivationCodes() {
int i = userActivationRepository.removeInvalidActivationCodes();
if (i > 0) {
LOGGER.info("Removed {} expired user activation codes", i);
}
}

@Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15)
public void clearInvalidPasswordResetTokens() {
int i = passwordResetRepository.removeInvalidPasswordResetTokens();
if (i > 0) {
LOGGER.info("Removed {} expired password reset tokens", i);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package it.chalmers.gamma.adapter.primary.web;

import it.chalmers.gamma.app.user.activation.ActivationCodeFacade;
import it.chalmers.gamma.app.user.allowlist.AllowListFacade;
import it.chalmers.gamma.app.user.allowlist.AllowListRepository;
import java.util.Comparator;
Expand All @@ -12,11 +13,16 @@
public class AllowListController {

private final AllowListFacade allowListFacade;
private final ActivationCodeFacade activationCodeFacade;

public AllowListController(AllowListFacade allowListFacade) {
public AllowListController(
AllowListFacade allowListFacade, ActivationCodeFacade activationCodeFacade) {
this.allowListFacade = allowListFacade;
this.activationCodeFacade = activationCodeFacade;
}

public record AllowListItem(String cid, boolean hasActivationCode) {}

@GetMapping("/allow-list")
public ModelAndView getAllowList(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) {
Expand All @@ -29,8 +35,17 @@ public ModelAndView getAllowList(
}

List<String> allowList = this.allowListFacade.getAllowList();
List<String> activationList =
this.activationCodeFacade.getAllUserActivations().stream()
.map(ActivationCodeFacade.UserActivationDTO::cid)
.toList();

mv.addObject(
"allowList", allowList.stream().sorted(Comparator.comparing(String::toLowerCase)).toList());
"allowList",
allowList.stream()
.sorted(Comparator.comparing(String::toLowerCase))
.map(cid -> new AllowListItem(cid, activationList.contains(cid)))
.toList());

return mv;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public UserClientsController(ClientFacade clientFacade) {
this.clientFacade = clientFacade;
}

public record UserClient(String prettyName, String ownerUserName, UUID clientUid) {
public record UserClient(String prettyName, String fullName, UUID userId, UUID clientUid) {
public UserClient(ClientFacade.ClientDTO client, UserFacade.UserDTO user) {
this(client.prettyName(), user.firstName() + " " + user.lastName(), client.clientUid());
this(client.prettyName(), user.fullName(), user.id(), client.clientUid());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,18 @@ public boolean isStillValid(UserActivationEntity userActivationEntity) {
public void removeActivation(Cid cid) throws CidNotActivatedException {
this.userActivationJpaRepository.deleteById(cid.value());
}

@Override
public int removeInvalidActivationCodes() {
int i = 0;

for (UserActivationEntity userActivationEntity : this.userActivationJpaRepository.findAll()) {
if (!isStillValid(userActivationEntity)) {
this.userActivationJpaRepository.delete(userActivationEntity);
i++;
}
}

return i;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ public UserId useToken(PasswordResetToken token) {
return new UserId(maybeReset.get().userId);
}

@Override
public int removeInvalidPasswordResetTokens() {
int i = 0;

for (UserPasswordResetEntity userPasswordResetEntity : this.userPasswordResetJpaRepository.findAll()) {
if (!isStillValid(userPasswordResetEntity)) {
this.userPasswordResetJpaRepository.delete(userPasswordResetEntity);
i++;
}
}

return i;
}

public boolean isStillValid(UserPasswordResetEntity userPasswordResetEntity) {
Instant createdAt = userPasswordResetEntity.toDomain().createdAt();
return Duration.between(createdAt, Instant.now()).toMinutes() < 15;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public interface UserActivationRepository {

void removeActivation(Cid cid) throws CidNotActivatedException;

int removeInvalidActivationCodes();

class TokenNotActivatedRuntimeException extends RuntimeException {}

class CidNotActivatedException extends RuntimeException {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ record PasswordReset(PasswordResetToken token, Email email) {}

UserId useToken(PasswordResetToken token);

int removeInvalidPasswordResetTokens();

class UserNotFoundException extends Exception {}

class TokenNotFoundRuntimeException extends RuntimeException {}
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/resources/templates/pages/allow-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
</thead>
<tbody>
<tr th:each="allowedCid : ${allowList}">
<td th:text="${allowedCid}"></td>
<td th:text="${allowedCid.cid()}"></td>
<td class="table-align-right">
<form th:data-hx-post="|/allow-list/${allowedCid}|" data-hx-target="closest tr" data-hx-swap="delete">
<span th:if="${allowedCid.hasActivationCode()}">
Has activation code
</span>
<form th:if="${!allowedCid.hasActivationCode()}" th:data-hx-post="|/allow-list/${allowedCid.cid()}|" data-hx-target="closest tr" data-hx-swap="delete">
<div th:replace="~{common/form-csrf}"></div>
<input type="hidden" name="_method" value="delete" />
<button class="outline contrast" data-loading-disable>Retract approval</button>
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/resources/templates/pages/user-clients.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
<tbody>
<tr th:each="client : ${clients}">
<td th:text="${client.prettyName()}"></td>
<td th:text="${client.ownerUserName()}"></td>
<td>
<a th:href="|/users/${client.userId()}|" th:text="${client.fullName()}"></a>
</td>
<td>
<a th:href="${'/clients/' + client.clientUid()}">Details</a>
</td>
Expand Down

0 comments on commit 3123030

Please sign in to comment.