Skip to content

Commit 3775d2f

Browse files
committed
Fixes #681
1 parent b6ba1d0 commit 3775d2f

5 files changed

Lines changed: 51 additions & 10 deletions

File tree

server/src/main/java/invite/cron/ResourceCleaner.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
import invite.audit.UserRoleAuditService;
55
import invite.model.Role;
6+
import invite.model.Status;
67
import invite.model.User;
78
import invite.model.UserRole;
89
import invite.model.UserRoleAudit;
910
import invite.provision.ProvisioningService;
10-
import invite.provision.scim.OperationType;
11+
import invite.repository.InvitationRepository;
1112
import invite.repository.UserRepository;
1213
import invite.repository.UserRoleAuditRepository;
1314
import invite.repository.UserRoleRepository;
@@ -20,7 +21,6 @@
2021
import org.springframework.transaction.annotation.Transactional;
2122

2223
import javax.sql.DataSource;
23-
import java.io.Serializable;
2424
import java.time.Instant;
2525
import java.time.Period;
2626
import java.util.List;
@@ -39,6 +39,8 @@ public class ResourceCleaner extends AbstractNodeLeader {
3939
private final UserRoleAuditService userRoleAuditService;
4040
private final int lastActivityDurationDays;
4141
private final int purgeAuditLogDays;
42+
private final int purgeExpiredInvitationDays;
43+
private final InvitationRepository invitationRepository;
4244

4345

4446
@Autowired
@@ -48,16 +50,21 @@ public ResourceCleaner(UserRepository userRepository,
4850
DataSource dataSource,
4951
UserRoleAuditRepository userRoleAuditRepository,
5052
UserRoleAuditService userRoleAuditService,
53+
InvitationRepository invitationRepository,
5154
@Value("${cron.last-activity-duration-days}") int lastActivityDurationDays,
52-
@Value("${cron.purge-audit-log-days}") int purgeAuditLogDays) {
55+
@Value("${cron.purge-audit-log-days}") int purgeAuditLogDays,
56+
@Value("${cron.purge-expired-invitations-days}") int purgeExpiredInvitationDays) {
5357
super(LOCK_NAME, dataSource);
5458
this.userRepository = userRepository;
5559
this.userRoleRepository = userRoleRepository;
5660
this.userRoleAuditRepository = userRoleAuditRepository;
5761
this.userRoleAuditService = userRoleAuditService;
5862
this.lastActivityDurationDays = lastActivityDurationDays;
5963
this.provisioningService = provisioningService;
60-
this.purgeAuditLogDays = purgeAuditLogDays; }
64+
this.purgeAuditLogDays = purgeAuditLogDays;
65+
this.purgeExpiredInvitationDays = purgeExpiredInvitationDays;
66+
this.invitationRepository = invitationRepository;
67+
}
6168

6269
@Scheduled(cron = "${cron.user-cleaner-expression}")
6370
@Transactional
@@ -73,7 +80,8 @@ public Map<String, Object> doClean() {
7380
"DeletedNonActiveUsers", users,
7481
"DeletedOrphanUsers", orphans,
7582
"DeletedExpiredUserRoles", userRoles,
76-
"DeletedUserRoleAudits", cleanUserRoleAudit()
83+
"DeletedUserRoleAudits", cleanUserRoleAudit(),
84+
"DeletedExpiredInvitations", cleanExpiredInvitation()
7785
);
7886
}
7987

@@ -132,4 +140,11 @@ private int cleanUserRoleAudit() {
132140
return userRoleAuditRepository.deleteByCreatedAtBefore(past);
133141
}
134142

143+
private int cleanExpiredInvitation() {
144+
if (purgeExpiredInvitationDays == 0L) {
145+
return 0;
146+
}
147+
Instant past = Instant.now().minus(Period.ofDays(purgeExpiredInvitationDays));
148+
return invitationRepository.deleteByExpiryDateBefore(past);
149+
}
135150
}

server/src/main/java/invite/repository/InvitationRepository.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.springframework.data.jpa.repository.QueryRewriter;
1616
import org.springframework.stereotype.Repository;
1717

18+
import java.time.Instant;
1819
import java.util.List;
1920
import java.util.Map;
2021
import java.util.Optional;
@@ -133,7 +134,7 @@ OR MATCH (u.given_name, u.family_name, u.email, u.schac_home_organization) again
133134
INNER JOIN roles r ON r.id = ir.role_id
134135
WHERE i.status = ?1 AND r.id = ?2 AND
135136
(UPPER(i.email) LIKE ?3 or UPPER(u.schac_home_organization) LIKE ?3
136-
or UPPER(u.email) LIKE ?3)
137+
or UPPER(u.email) LIKE ?3)
137138
""",
138139
countQuery = """
139140
SELECT count(*) FROM invitations i
@@ -142,7 +143,7 @@ SELECT count(*) FROM invitations i
142143
LEFT JOIN users u ON u.id = i.inviter_id
143144
WHERE status = ?1 and role_id = ?2 AND
144145
(UPPER(i.email) LIKE ?3 or UPPER(u.schac_home_organization) LIKE ?3
145-
or UPPER(u.email) LIKE ?3)
146+
or UPPER(u.email) LIKE ?3)
146147
""",
147148
queryRewriter = InvitationRepository.class,
148149
nativeQuery = true)
@@ -157,6 +158,8 @@ or UPPER(u.email) LIKE ?3)
157158
""", nativeQuery = true)
158159
List<Map<String, Object>> findRoles(List<Long> invitationIdentifiers);
159160

161+
int deleteByExpiryDateBefore(Instant cutoff);
162+
160163
@Override
161164
default String rewrite(String query, Sort sort) {
162165
Sort.Order nameSort = sort.getOrderFor("name");

server/src/main/resources/application.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ cron:
8888
metadata-resolver-url: "classpath:/metadata/idps-metadata.xml"
8989
# A value of 0 means no logs will be deleted
9090
purge-audit-log-days: 365
91+
# A value of 0 means no invitations will be deleted
92+
purge-expired-invitations-days: 365
9193

9294
myconext:
9395
uri: "https://login.test2.eduid.nl/myconext/api/invite/provision-eduid"

server/src/test/java/invite/cron/ResourceCleanerTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.core.JsonProcessingException;
44
import invite.AbstractTest;
5+
import invite.model.Invitation;
56
import invite.model.User;
67
import invite.model.UserRoleAudit;
78
import lombok.SneakyThrows;
@@ -88,6 +89,19 @@ void cleanUserRoleAudits() {
8889
assertEquals(0, userRoleAuditRepository.count());
8990
}
9091

92+
@Test
93+
void cleanExpiredInvitations() {
94+
long count = invitationRepository.count();
95+
Instant past = Instant.now().minus(400, ChronoUnit.DAYS);
96+
Invitation invitation = invitationRepository.findByHash(GRAPH_INVITATION_HASH).get();
97+
invitation.setExpiryDate(past);
98+
invitationRepository.save(invitation);
99+
100+
resourceCleaner.clean();
101+
102+
assertEquals(count - 1, invitationRepository.count());
103+
}
104+
91105
@SneakyThrows
92106
@Test
93107
void lockAlreadyAcquired() {

server/src/test/java/invite/cron/ResourceCleanerUnitTest.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import invite.model.UserRole;
88
import invite.provision.ProvisioningService;
99
import invite.provision.scim.OperationType;
10+
import invite.repository.InvitationRepository;
1011
import invite.repository.UserRepository;
1112
import invite.repository.UserRoleAuditRepository;
1213
import invite.repository.UserRoleRepository;
@@ -29,6 +30,7 @@ class ResourceCleanerUnitTest {
2930

3031
private final UserRepository userRepository = mock(UserRepository.class);
3132
private final UserRoleRepository userRoleRepository = mock(UserRoleRepository.class);
33+
private final InvitationRepository invitationRepository = mock(InvitationRepository.class);
3234
private final UserRoleAuditRepository userRoleAuditRepository = mock(UserRoleAuditRepository.class);
3335
private final ProvisioningService provisioningService = mock(ProvisioningService.class);
3436
private final UserRoleAuditService userRoleAuditService = new UserRoleAuditService(userRoleAuditRepository);
@@ -41,12 +43,15 @@ class ResourceCleanerUnitTest {
4143
dataSource,
4244
userRoleAuditRepository,
4345
userRoleAuditService,
46+
invitationRepository,
47+
5,
4448
5,
4549
5);
4650

4751

4852
@SneakyThrows
4953
@Test
54+
@SuppressWarnings("raw")
5055
void cleanUsers() {
5156
List<User> users = List.of(new User(), new User());
5257
when(userRepository.findByLastActivityBefore(any(Instant.class)))
@@ -56,6 +61,7 @@ void cleanUsers() {
5661
when(userRoleRepository.findByEndDateBeforeAndExpiryNotifications(any(Instant.class), eq(1)))
5762
.thenReturn(List.of(new UserRole("Inviter", new User(), new Role(), Authority.INVITER)));
5863
when(userRoleAuditRepository.deleteByCreatedAtBefore(any(Instant.class))).thenReturn(5);
64+
when(invitationRepository.deleteByExpiryDateBefore(any(Instant.class))).thenReturn(3);
5965
doNothing().when(provisioningService).deleteUserRequest(any(User.class));
6066
doNothing().when(provisioningService).updateGroupRequest(any(UserRole.class), any(OperationType.class));
6167

@@ -80,10 +86,11 @@ void cleanUsers() {
8086
.updateGroupRequest(any(UserRole.class), eq(OperationType.remove));
8187

8288
Map<String, Object> results = subject.doClean();
83-
assertEquals(2, ((List) results.get("DeletedNonActiveUsers")).size());
84-
assertEquals(2, ((List) results.get("DeletedOrphanUsers")).size());
85-
assertEquals(1, ((List) results.get("DeletedExpiredUserRoles")).size());
89+
assertEquals(2, ((List<?>) results.get("DeletedNonActiveUsers")).size());
90+
assertEquals(2, ((List<?>) results.get("DeletedOrphanUsers")).size());
91+
assertEquals(1, ((List<?>) results.get("DeletedExpiredUserRoles")).size());
8692
assertEquals(5, (int) results.get("DeletedUserRoleAudits"));
93+
assertEquals(3, (int) results.get("DeletedExpiredInvitations"));
8794
}
8895

8996
}

0 commit comments

Comments
 (0)