Merge branch 'refs/heads/24-fix-achievement-date' into sattelgeschichten

This commit is contained in:
Marcus Fihlon 2026-04-29 12:19:12 +02:00
commit 816803f3f0
Signed by: McPringle
GPG key ID: C6B7F469EE363E1F
2 changed files with 47 additions and 5 deletions

View file

@ -41,10 +41,8 @@ public class AchievementService {
*/ */
@Transactional @Transactional
public List<Achievement> checkAndAwardAchievements(Activity activity) { public List<Achievement> checkAndAwardAchievements(Activity activity) {
List<Achievement> newAchievements = new ArrayList<>();
if (activity.getUserId() == null || activity.getStartedAt() == null || activity.getEndedAt() == null) { if (activity.getUserId() == null || activity.getStartedAt() == null || activity.getEndedAt() == null) {
return newAchievements; return List.of();
} }
UUID userId = activity.getUserId(); UUID userId = activity.getUserId();
@ -59,6 +57,15 @@ public class AchievementService {
existing.add(a.getAchievementType()); existing.add(a.getAchievementType());
} }
return checkAndAwardAchievements(activity, progress, existing);
}
private List<Achievement> checkAndAwardAchievements(Activity activity,
ActivityProgress progress,
Set<Achievement.AchievementType> existing) {
List<Achievement> newAchievements = new ArrayList<>();
UUID userId = activity.getUserId();
// Check first activity achievements // Check first activity achievements
newAchievements.addAll(checkFirstActivityAchievements(userId, activity, progress, existing)); newAchievements.addAll(checkFirstActivityAchievements(userId, activity, progress, existing));
@ -83,6 +90,10 @@ public class AchievementService {
// Check speed achievements // Check speed achievements
newAchievements.addAll(checkSpeedAchievements(userId, activity, progress, existing)); newAchievements.addAll(checkSpeedAchievements(userId, activity, progress, existing));
for (Achievement achievement : newAchievements) {
existing.add(achievement.getAchievementType());
}
return newAchievements; return newAchievements;
} }
@ -103,9 +114,15 @@ public class AchievementService {
achievementRepository.deleteByUserId(userId); achievementRepository.deleteByUserId(userId);
Set<Achievement.AchievementType> existing = EnumSet.noneOf(Achievement.AchievementType.class);
List<Achievement> rebuiltAchievements = new ArrayList<>(); List<Achievement> rebuiltAchievements = new ArrayList<>();
for (Activity activity : activityHistory) { for (int i = 0; i < activityHistory.size(); i++) {
rebuiltAchievements.addAll(checkAndAwardAchievements(activity)); Activity activity = activityHistory.get(i);
rebuiltAchievements.addAll(checkAndAwardAchievements(
activity,
ActivityProgress.fromHistory(activityHistory, i),
existing
));
} }
return rebuiltAchievements; return rebuiltAchievements;
@ -560,6 +577,10 @@ public class AchievementService {
throw new IllegalStateException("Current activity missing from chronological history: " + currentActivity.getId()); throw new IllegalStateException("Current activity missing from chronological history: " + currentActivity.getId());
} }
return fromHistory(activityHistory, currentIndex);
}
private static ActivityProgress fromHistory(List<Activity> activityHistory, int currentIndex) {
return new ActivityProgress( return new ActivityProgress(
List.copyOf(activityHistory.subList(0, currentIndex)), List.copyOf(activityHistory.subList(0, currentIndex)),
List.copyOf(activityHistory.subList(0, currentIndex + 1)) List.copyOf(activityHistory.subList(0, currentIndex + 1))

View file

@ -414,6 +414,27 @@ class AchievementServiceTest {
inOrder.verify(achievementRepository, atLeastOnce()).save(any(Achievement.class)); inOrder.verify(achievementRepository, atLeastOnce()).save(any(Achievement.class));
} }
@Test
@DisplayName("Should rebuild achievements from a stable history snapshot")
void testRebuildAchievementsForUser_UsesStableHistorySnapshot() {
Activity previous = createActivity(Activity.ActivityType.RUN, 9000L, BigDecimal.ZERO);
previous.setStartedAt(LocalDateTime.of(2025, 11, 30, 10, 0));
previous.setEndedAt(LocalDateTime.of(2025, 11, 30, 11, 0));
Activity activity = createActivity(Activity.ActivityType.RUN, 2000L, BigDecimal.ZERO);
activity.setStartedAt(LocalDateTime.of(2025, 12, 1, 7, 15));
activity.setEndedAt(LocalDateTime.of(2025, 12, 1, 8, 5));
when(activityRepository.findByUserIdOrderByStartedAtAsc(userId))
.thenReturn(List.of(previous, activity))
.thenReturn(List.of(previous));
when(achievementRepository.save(any(Achievement.class))).thenAnswer(invocation -> invocation.getArgument(0));
List<Achievement> rebuilt = achievementService.rebuildAchievementsForUser(userId);
assertTrue(rebuilt.stream().anyMatch(a -> a.getAchievementType() == Achievement.AchievementType.DISTANCE_10K));
verify(activityRepository, times(1)).findByUserIdOrderByStartedAtAsc(userId);
}
@Test @Test
@DisplayName("Should get user achievements") @DisplayName("Should get user achievements")
void testGetUserAchievements() { void testGetUserAchievements() {