Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [390] - Purge non-confirmed users periodically #402

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/com/nonononoki/alovoa/repo/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ default List<User> usersSearch(UserSearchRequest request, Pageable page) {
request.getLikeIds(), request.getHideIds(), request.getBlockIds(), request.getGenderIds(), page);
}

List<User> findByConfirmedIsFalseAndDatesCreationDateBefore(Date date);

@Query(value = "SELECT u FROM User u WHERE u.disabled = FALSE AND u.admin = FALSE AND u.confirmed = TRUE AND u.intention IS NOT NULL AND "
+ "u.locationLatitude IS NOT NULL AND u.locationLongitude IS NOT NULL AND u.profilePicture IS NOT NULL "
+ "AND TIMESTAMPDIFF(YEAR, u.dates.dateOfBirth, CURDATE()) + u.preferedMaxAge >= :age AND TIMESTAMPDIFF(YEAR, u.dates.dateOfBirth, CURDATE()) + u.preferedMinAge <= :age AND u.dates.dateOfBirth >= :minDate AND u.dates.dateOfBirth <= :maxDate "
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/nonononoki/alovoa/service/ScheduleService.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public class ScheduleService {
@Value("${app.schedule.delay.contact}")
private long contactDelay;

@Value("${app.schedule.delay.user.cleanup:}")
private long nonConfirmedUsersCleanupDelay;

private static final int HIDE_MAX = 20;

@Scheduled(fixedDelayString = "${app.schedule.short}")
Expand All @@ -63,9 +66,21 @@ public void scheduleLong() {
if (enableSchedules) {
Date date = new Date();
cleanContact(date);
cleanNonConfirmedUsers(date);
}
}

public void cleanNonConfirmedUsers(final Date date) {
long ms = date.getTime();
ms -= nonConfirmedUsersCleanupDelay;
Date d = new Date(ms);

List<User> users = userRepo.findByConfirmedIsFalseAndDatesCreationDateBefore(d);

userRepo.deleteAll(users);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be a good idea to double check before purging user... you know, to avoid risking purging the whole database in the case of "userRepo.findByConfirmedIsFalseAndDatesCreationDateBefore" not being restrictive enough. Btw, were is this query implemented? I can't find it on the PR diff.

userRepo.flush();
}

public void cleanCaptcha(Date date) {
long ms = date.getTime();
ms -= captchaDelay;
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,5 @@ app.schedule.delay.captcha=300000
app.schedule.delay.hide=9720000000
#90 days
app.schedule.delay.contact=9720000000
#14 days
app.schedule.delay.user.cleanup=1209600000
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import com.nonononoki.alovoa.model.AlovoaException;
import jakarta.mail.MessagingException;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
Expand Down Expand Up @@ -157,29 +160,52 @@ public static List<User> getTestUsers(CaptchaService captchaService, RegisterSer
return testUsers;
}

public static List<User> createMockNewUsers(CaptchaService captchaService, RegisterService registerService,
int numberOfUsersToCreate) throws Exception {
List<User> newUsers = new ArrayList<>();

for (int i = 0; i < numberOfUsersToCreate; ++i) {
String userEmail = "non0" + i + "nonoki@gmail.com";
// register and confirm test users
Captcha c1 = captchaService.generate();
RegisterDto user1Dto = createTestUserDto(1, c1, userEmail, USER1_AGE + i);
String tokenContent1 = registerService.register(user1Dto);
User user = registerService.registerConfirm(tokenContent1);
newUsers.add(user);
}

return newUsers;
}

public static void deleteAllUsers(UserService userService, AuthService authService, CaptchaService captchaService,
ConversationRepository conversationRepo, UserRepository userRepo) throws Exception {
if (testUsers != null) {
for (User user : testUsers) {
if (!user.isAdmin()) {
user = userRepo.findById(user.getId()).get();
Mockito.when(authService.getCurrentUser()).thenReturn(user);
Mockito.when(authService.getCurrentUser(true)).thenReturn(user);
UserDeleteToken token = userService.deleteAccountRequest();
UserDeleteAccountDto dto = new UserDeleteAccountDto();
Captcha captcha = captchaService.generate();
dto.setCaptchaId(captcha.getId());
dto.setCaptchaText(captcha.getText());
dto.setConfirm(true);
dto.setEmail(user.getEmail());
dto.setTokenString(token.getContent());
userService.deleteAccountConfirm(dto);
}
deleteGivenUser(user, userService, userRepo, captchaService, authService);
}

testUsers = null;
}
}

public static void deleteGivenUser(User user, final UserService userService, final UserRepository userRepo,
final CaptchaService captchaService, final AuthService authService) throws Exception {
if (!user.isAdmin()) {
user = userRepo.findById(user.getId()).get();
Mockito.when(authService.getCurrentUser()).thenReturn(user);
Mockito.when(authService.getCurrentUser(true)).thenReturn(user);
UserDeleteToken token = userService.deleteAccountRequest();
UserDeleteAccountDto dto = new UserDeleteAccountDto();
Captcha captcha = captchaService.generate();
dto.setCaptchaId(captcha.getId());
dto.setCaptchaText(captcha.getText());
dto.setConfirm(true);
dto.setEmail(user.getEmail());
dto.setTokenString(token.getContent());
userService.deleteAccountConfirm(dto);
}
}

private static RegisterDto createTestUserDto(long gender, Captcha c, String email, int age) throws IOException {
RegisterDto dto = new RegisterDto();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

Expand Down Expand Up @@ -164,6 +165,39 @@ void test() throws Exception {
assertEquals(1, userHideRepo.count());
}

@Test
public void testScheduleLong() throws Exception {
// CLEAN-UP NON-CONFIRMED USERS
var mockNewUsers = RegisterServiceTest.createMockNewUsers(captchaService, registerService, 3);
User mockUser1 = mockNewUsers.get(0);
User mockUser2 = mockNewUsers.get(1);
User mockUser3 = mockNewUsers.get(2);

try {
// Non-confirmed user with more than 15 days creation date
mockUser1.setConfirmed(false);
var dates = mockUser1.getDates();
dates.setCreationDate(addUnitsToDate(dates.getCreationDate(), Calendar.DATE, -15));

// Non-confirmed user with 14 days creation date
mockUser2.setConfirmed(false);
dates = mockUser2.getDates();
dates.setCreationDate(addUnitsToDate(dates.getCreationDate(), Calendar.DATE, -14));

// Confirmed user with more than 15 days creation date
mockUser3.setConfirmed(true);
dates = mockUser3.getDates();
dates.setCreationDate(addUnitsToDate(dates.getCreationDate(), Calendar.DATE, -15));
userRepo.saveAllAndFlush(List.of(mockUser1, mockUser2, mockUser3));
var initialCount = userRepo.count();

scheduleService.cleanNonConfirmedUsers(new Date());
assertEquals(2, (initialCount - userRepo.count()));
} finally {
RegisterServiceTest.deleteGivenUser(mockUser3, userService, userRepo, captchaService, authService);
}
}

private Captcha generateCaptcha(String hashCode) {
Captcha captcha = new Captcha();
captcha.setDate(new Date());
Expand All @@ -173,4 +207,12 @@ private Captcha generateCaptcha(String hashCode) {
captcha = captchaRepo.saveAndFlush(captcha);
return captcha;
}

private static Date addUnitsToDate(final Date inputDate, final int unitField, final int unitAmount) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(inputDate);
calendar.add(unitField, unitAmount);

return calendar.getTime();
}
}
Loading