Merge branch 'refs/heads/24-fix-achievement-date' into sattelgeschichten
This commit is contained in:
commit
bda2ab13cf
5 changed files with 65 additions and 1 deletions
|
|
@ -35,6 +35,11 @@ public interface PersonalRecordRepository extends JpaRepository<PersonalRecord,
|
||||||
PersonalRecord.RecordType recordType
|
PersonalRecord.RecordType recordType
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all personal records for a user.
|
||||||
|
*/
|
||||||
|
void deleteByUserId(UUID userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get count of personal records set by a user.
|
* Get count of personal records set by a user.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ public class ActivityDeleteRecalculationService {
|
||||||
|
|
||||||
private final AchievementService achievementService;
|
private final AchievementService achievementService;
|
||||||
private final ActivitySummaryService activitySummaryService;
|
private final ActivitySummaryService activitySummaryService;
|
||||||
|
private final PersonalRecordService personalRecordService;
|
||||||
private final ConcurrentMap<UUID, PendingUserRecalculation> pendingRecalculations = new ConcurrentHashMap<>();
|
private final ConcurrentMap<UUID, PendingUserRecalculation> pendingRecalculations = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
|
|
@ -42,6 +43,7 @@ public class ActivityDeleteRecalculationService {
|
||||||
do {
|
do {
|
||||||
Set<LocalDate> datesToRecalculate = pending.drainDates();
|
Set<LocalDate> datesToRecalculate = pending.drainDates();
|
||||||
achievementService.rebuildAchievementsForUser(event.userId());
|
achievementService.rebuildAchievementsForUser(event.userId());
|
||||||
|
personalRecordService.rebuildPersonalRecordsForUser(event.userId());
|
||||||
for (LocalDate date : datesToRecalculate) {
|
for (LocalDate date : datesToRecalculate) {
|
||||||
activitySummaryService.updateWeeklySummary(event.userId(), date);
|
activitySummaryService.updateWeeklySummary(event.userId(), date);
|
||||||
activitySummaryService.updateMonthlySummary(event.userId(), date);
|
activitySummaryService.updateMonthlySummary(event.userId(), date);
|
||||||
|
|
@ -49,7 +51,7 @@ public class ActivityDeleteRecalculationService {
|
||||||
}
|
}
|
||||||
} while (pending.keepProcessing());
|
} while (pending.keepProcessing());
|
||||||
|
|
||||||
log.info("Recalculated achievements and summaries after deleting activities for user {}", event.userId());
|
log.info("Recalculated achievements, personal records, and summaries after deleting activities for user {}", event.userId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class PendingUserRecalculation {
|
private static final class PendingUserRecalculation {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.javahippie.fitpub.model.entity.Activity;
|
import net.javahippie.fitpub.model.entity.Activity;
|
||||||
import net.javahippie.fitpub.model.entity.PersonalRecord;
|
import net.javahippie.fitpub.model.entity.PersonalRecord;
|
||||||
|
import net.javahippie.fitpub.repository.ActivityRepository;
|
||||||
import net.javahippie.fitpub.repository.PersonalRecordRepository;
|
import net.javahippie.fitpub.repository.PersonalRecordRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
@ -23,6 +24,7 @@ import java.util.UUID;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PersonalRecordService {
|
public class PersonalRecordService {
|
||||||
|
|
||||||
|
private final ActivityRepository activityRepository;
|
||||||
private final PersonalRecordRepository personalRecordRepository;
|
private final PersonalRecordRepository personalRecordRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -320,4 +322,19 @@ public class PersonalRecordService {
|
||||||
public long getPersonalRecordCount(UUID userId) {
|
public long getPersonalRecordCount(UUID userId) {
|
||||||
return personalRecordRepository.countByUserId(userId);
|
return personalRecordRepository.countByUserId(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuild all personal records for a user from remaining activities.
|
||||||
|
*/
|
||||||
|
@Transactional
|
||||||
|
public void rebuildPersonalRecordsForUser(UUID userId) {
|
||||||
|
personalRecordRepository.deleteByUserId(userId);
|
||||||
|
|
||||||
|
List<Activity> activities = activityRepository.findByUserIdOrderByStartedAtAsc(userId);
|
||||||
|
for (Activity activity : activities) {
|
||||||
|
checkAndUpdatePersonalRecords(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Rebuilt personal records for user {} from {} activities", userId, activities.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ class ActivityDeleteRecalculationServiceTest {
|
||||||
@Mock
|
@Mock
|
||||||
private ActivitySummaryService activitySummaryService;
|
private ActivitySummaryService activitySummaryService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PersonalRecordService personalRecordService;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private ActivityDeleteRecalculationService activityDeleteRecalculationService;
|
private ActivityDeleteRecalculationService activityDeleteRecalculationService;
|
||||||
|
|
||||||
|
|
@ -36,6 +39,7 @@ class ActivityDeleteRecalculationServiceTest {
|
||||||
activityDeleteRecalculationService.handleActivityDeleted(new ActivityDeletedEvent(userId, activityDate));
|
activityDeleteRecalculationService.handleActivityDeleted(new ActivityDeletedEvent(userId, activityDate));
|
||||||
|
|
||||||
verify(achievementService).rebuildAchievementsForUser(userId);
|
verify(achievementService).rebuildAchievementsForUser(userId);
|
||||||
|
verify(personalRecordService).rebuildPersonalRecordsForUser(userId);
|
||||||
verify(activitySummaryService).updateWeeklySummary(userId, activityDate);
|
verify(activitySummaryService).updateWeeklySummary(userId, activityDate);
|
||||||
verify(activitySummaryService).updateMonthlySummary(userId, activityDate);
|
verify(activitySummaryService).updateMonthlySummary(userId, activityDate);
|
||||||
verify(activitySummaryService).updateYearlySummary(userId, activityDate);
|
verify(activitySummaryService).updateYearlySummary(userId, activityDate);
|
||||||
|
|
@ -59,6 +63,7 @@ class ActivityDeleteRecalculationServiceTest {
|
||||||
activityDeleteRecalculationService.handleActivityDeleted(new ActivityDeletedEvent(userId, firstDate));
|
activityDeleteRecalculationService.handleActivityDeleted(new ActivityDeletedEvent(userId, firstDate));
|
||||||
|
|
||||||
verify(achievementService, times(2)).rebuildAchievementsForUser(userId);
|
verify(achievementService, times(2)).rebuildAchievementsForUser(userId);
|
||||||
|
verify(personalRecordService, times(2)).rebuildPersonalRecordsForUser(userId);
|
||||||
verify(activitySummaryService).updateWeeklySummary(userId, firstDate);
|
verify(activitySummaryService).updateWeeklySummary(userId, firstDate);
|
||||||
verify(activitySummaryService).updateMonthlySummary(userId, firstDate);
|
verify(activitySummaryService).updateMonthlySummary(userId, firstDate);
|
||||||
verify(activitySummaryService).updateYearlySummary(userId, firstDate);
|
verify(activitySummaryService).updateYearlySummary(userId, firstDate);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import net.javahippie.fitpub.model.entity.Activity;
|
import net.javahippie.fitpub.model.entity.Activity;
|
||||||
import net.javahippie.fitpub.model.entity.ActivityMetrics;
|
import net.javahippie.fitpub.model.entity.ActivityMetrics;
|
||||||
import net.javahippie.fitpub.model.entity.PersonalRecord;
|
import net.javahippie.fitpub.model.entity.PersonalRecord;
|
||||||
|
import net.javahippie.fitpub.repository.ActivityRepository;
|
||||||
import net.javahippie.fitpub.repository.PersonalRecordRepository;
|
import net.javahippie.fitpub.repository.PersonalRecordRepository;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
@ -33,6 +34,9 @@ class PersonalRecordServiceTest {
|
||||||
@Mock
|
@Mock
|
||||||
private PersonalRecordRepository personalRecordRepository;
|
private PersonalRecordRepository personalRecordRepository;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ActivityRepository activityRepository;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private PersonalRecordService personalRecordService;
|
private PersonalRecordService personalRecordService;
|
||||||
|
|
||||||
|
|
@ -415,6 +419,37 @@ class PersonalRecordServiceTest {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should rebuild personal records from remaining activities")
|
||||||
|
void testRebuildPersonalRecordsForUser() {
|
||||||
|
Activity firstActivity = createActivity(
|
||||||
|
10000L,
|
||||||
|
3600L,
|
||||||
|
BigDecimal.valueOf(100)
|
||||||
|
);
|
||||||
|
firstActivity.setStartedAt(testTime.minusDays(2));
|
||||||
|
|
||||||
|
Activity secondActivity = createActivity(
|
||||||
|
15000L,
|
||||||
|
4500L,
|
||||||
|
BigDecimal.valueOf(200)
|
||||||
|
);
|
||||||
|
secondActivity.setStartedAt(testTime.minusDays(1));
|
||||||
|
|
||||||
|
when(activityRepository.findByUserIdOrderByStartedAtAsc(userId))
|
||||||
|
.thenReturn(List.of(firstActivity, secondActivity));
|
||||||
|
when(personalRecordRepository.findByUserIdAndActivityTypeAndRecordType(any(), any(), any()))
|
||||||
|
.thenReturn(Optional.empty());
|
||||||
|
when(personalRecordRepository.save(any(PersonalRecord.class)))
|
||||||
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||||
|
|
||||||
|
personalRecordService.rebuildPersonalRecordsForUser(userId);
|
||||||
|
|
||||||
|
verify(personalRecordRepository).deleteByUserId(userId);
|
||||||
|
verify(activityRepository).findByUserIdOrderByStartedAtAsc(userId);
|
||||||
|
verify(personalRecordRepository, atLeastOnce()).save(any(PersonalRecord.class));
|
||||||
|
}
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
|
|
||||||
private Activity createActivity(long distanceMeters, long durationSeconds, BigDecimal elevationGain) {
|
private Activity createActivity(long distanceMeters, long durationSeconds, BigDecimal elevationGain) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue