Add Komoot activity import with guided browser-based batch flow #25
8 changed files with 155 additions and 93 deletions
|
|
@ -43,7 +43,7 @@ public class KomootImportController {
|
||||||
.getId();
|
.getId();
|
||||||
|
|
||||||
log.info("User {} requested Komoot activity preview for Komoot ID {}",
|
log.info("User {} requested Komoot activity preview for Komoot ID {}",
|
||||||
authentication.getName(), request.userId());
|
authentication.getName(), request.getUserId());
|
||||||
KomootActivitiesResponse response = komootImportService.fetchCompletedActivities(request, fitPubUserId);
|
KomootActivitiesResponse response = komootImportService.fetchCompletedActivities(request, fitPubUserId);
|
||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ public class KomootImportController {
|
||||||
.getId();
|
.getId();
|
||||||
|
|
||||||
log.info("User {} requested Komoot import for activity {}",
|
log.info("User {} requested Komoot import for activity {}",
|
||||||
authentication.getName(), request.activityId());
|
authentication.getName(), request.getActivityId());
|
||||||
|
|
||||||
KomootImportExecutionResponse response = komootImportService.importActivity(
|
KomootImportExecutionResponse response = komootImportService.importActivity(
|
||||||
request,
|
request,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,22 @@
|
||||||
package net.javahippie.fitpub.model.dto;
|
package net.javahippie.fitpub.model.dto;
|
||||||
|
Okay, I'll switch the implementation to classes to mimic the esisting ones. Okay, I'll switch the implementation to classes to mimic the esisting ones.
|
|||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response payload for the Komoot import preview.
|
* Response payload for the Komoot import preview.
|
||||||
*/
|
*/
|
||||||
public record KomootActivitiesResponse(
|
@Data
|
||||||
String userId,
|
@Builder
|
||||||
int totalCount,
|
@NoArgsConstructor
|
||||||
List<KomootActivitySummaryDTO> activities
|
@AllArgsConstructor
|
||||||
) {
|
public class KomootActivitiesResponse {
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
private int totalCount;
|
||||||
|
private List<KomootActivitySummaryDTO> activities;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,33 @@ import jakarta.validation.constraints.Email;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Pattern;
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request payload for importing one specific Komoot activity.
|
* Request payload for importing one specific Komoot activity.
|
||||||
*
|
*
|
||||||
* <p>The password is only used for the current request and is never persisted.</p>
|
* <p>The password is only used for the current request and is never persisted.</p>
|
||||||
*/
|
*/
|
||||||
public record KomootActivityImportRequest(
|
@Data
|
||||||
@NotBlank
|
@Builder
|
||||||
@Email
|
@NoArgsConstructor
|
||||||
String email,
|
@AllArgsConstructor
|
||||||
|
public class KomootActivityImportRequest {
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
String password,
|
@Email
|
||||||
|
private String email;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Pattern(regexp = "\\d+", message = "Komoot user ID must contain digits only")
|
private String password;
|
||||||
String userId,
|
|
||||||
|
|
||||||
@NotNull
|
@NotBlank
|
||||||
Long activityId
|
@Pattern(regexp = "\\d+", message = "Komoot user ID must contain digits only")
|
||||||
) {
|
private String userId;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Long activityId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,33 @@
|
||||||
package net.javahippie.fitpub.model.dto;
|
package net.javahippie.fitpub.model.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reduced activity representation returned by the Komoot import preview.
|
* Reduced activity representation returned by the Komoot import preview.
|
||||||
*/
|
*/
|
||||||
public record KomootActivitySummaryDTO(
|
@Data
|
||||||
long id,
|
@Builder
|
||||||
String name,
|
@NoArgsConstructor
|
||||||
String sport,
|
@AllArgsConstructor
|
||||||
String mappedActivityType,
|
public class KomootActivitySummaryDTO {
|
||||||
String status,
|
|
||||||
String type,
|
private long id;
|
||||||
OffsetDateTime date,
|
private String name;
|
||||||
Double distanceMeters,
|
private String sport;
|
||||||
Integer durationSeconds,
|
private String mappedActivityType;
|
||||||
Integer timeInMotionSeconds,
|
private String status;
|
||||||
Double elevationUp,
|
private String type;
|
||||||
boolean imported,
|
private OffsetDateTime date;
|
||||||
UUID fitPubActivityId
|
private Double distanceMeters;
|
||||||
) {
|
private Integer durationSeconds;
|
||||||
|
private Integer timeInMotionSeconds;
|
||||||
|
private Double elevationUp;
|
||||||
|
private boolean imported;
|
||||||
|
private UUID fitPubActivityId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,23 @@
|
||||||
package net.javahippie.fitpub.model.dto;
|
package net.javahippie.fitpub.model.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response for importing exactly one Komoot activity into FitPub.
|
* Response for importing exactly one Komoot activity into FitPub.
|
||||||
*/
|
*/
|
||||||
public record KomootImportExecutionResponse(
|
@Data
|
||||||
UUID importedActivityId,
|
@Builder
|
||||||
Long importedKomootActivityId,
|
@NoArgsConstructor
|
||||||
String status,
|
@AllArgsConstructor
|
||||||
String message
|
public class KomootImportExecutionResponse {
|
||||||
) {
|
|
||||||
|
private UUID importedActivityId;
|
||||||
|
private Long importedKomootActivityId;
|
||||||
|
private String status;
|
||||||
|
private String message;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
package net.javahippie.fitpub.model.dto;
|
package net.javahippie.fitpub.model.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.AssertTrue;
|
||||||
import jakarta.validation.constraints.Email;
|
import jakarta.validation.constraints.Email;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.Pattern;
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
|
@ -11,23 +15,46 @@ import java.time.LocalDate;
|
||||||
*
|
*
|
||||||
* <p>The password is only used for the current request and is never persisted.</p>
|
* <p>The password is only used for the current request and is never persisted.</p>
|
||||||
*/
|
*/
|
||||||
public record KomootImportRequest(
|
@Data
|
||||||
@NotBlank
|
@Builder
|
||||||
@Email
|
@NoArgsConstructor
|
||||||
String email,
|
public class KomootImportRequest {
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
String password,
|
@Email
|
||||||
|
private String email;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Pattern(regexp = "\\d+", message = "Komoot user ID must contain digits only")
|
private String password;
|
||||||
String userId,
|
|
||||||
|
|
||||||
LocalDate startDate,
|
@NotBlank
|
||||||
|
@Pattern(regexp = "\\d+", message = "Komoot user ID must contain digits only")
|
||||||
|
private String userId;
|
||||||
|
|
||||||
LocalDate endDate
|
private LocalDate startDate;
|
||||||
) {
|
|
||||||
public KomootImportRequest {
|
private LocalDate endDate;
|
||||||
|
|
||||||
|
public KomootImportRequest(String email, String password, String userId, LocalDate startDate, LocalDate endDate) {
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.userId = userId;
|
||||||
|
this.startDate = startDate;
|
||||||
|
this.endDate = endDate;
|
||||||
|
validateDateRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssertTrue(message = "Start date and end date must either both be set or both be empty, and start date must be before or equal to end date.")
|
||||||
|
public boolean isDateRangeConsistent() {
|
||||||
|
try {
|
||||||
|
validateDateRange();
|
||||||
|
return true;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateDateRange() {
|
||||||
boolean onlyOneDateProvided = (startDate == null) != (endDate == null);
|
boolean onlyOneDateProvided = (startDate == null) != (endDate == null);
|
||||||
if (onlyOneDateProvided) {
|
if (onlyOneDateProvided) {
|
||||||
throw new IllegalArgumentException("Start date and end date must either both be set or both be empty.");
|
throw new IllegalArgumentException("Start date and end date must either both be set or both be empty.");
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ public class KomootImportService {
|
||||||
}
|
}
|
||||||
|
|
||||||
URI nextUri = buildInitialUri(request);
|
URI nextUri = buildInitialUri(request);
|
||||||
HttpEntity<Void> httpEntity = new HttpEntity<>(buildHeaders(request.email(), request.password()));
|
HttpEntity<Void> httpEntity = new HttpEntity<>(buildHeaders(request.getEmail(), request.getPassword()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (nextUri != null) {
|
while (nextUri != null) {
|
||||||
|
|
@ -113,8 +113,8 @@ public class KomootImportService {
|
||||||
throw new IllegalStateException("Failed to parse Komoot activity list.", e);
|
throw new IllegalStateException("Failed to parse Komoot activity list.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Fetched {} completed Komoot activities for user ID {}", activities.size(), request.userId());
|
log.info("Fetched {} completed Komoot activities for user ID {}", activities.size(), request.getUserId());
|
||||||
return new KomootActivitiesResponse(request.userId(), activities.size(), activities);
|
return new KomootActivitiesResponse(request.getUserId(), activities.size(), activities);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pauseBeforeNextPageRequest() {
|
void pauseBeforeNextPageRequest() {
|
||||||
|
|
@ -122,29 +122,29 @@ public class KomootImportService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public KomootImportExecutionResponse importActivity(KomootActivityImportRequest request, UUID fitPubUserId) {
|
public KomootImportExecutionResponse importActivity(KomootActivityImportRequest request, UUID fitPubUserId) {
|
||||||
Activity existingActivity = activityRepository.findByUserIdAndKomootActivityId(fitPubUserId, request.activityId()).orElse(null);
|
Activity existingActivity = activityRepository.findByUserIdAndKomootActivityId(fitPubUserId, request.getActivityId()).orElse(null);
|
||||||
if (existingActivity != null) {
|
if (existingActivity != null) {
|
||||||
return new KomootImportExecutionResponse(
|
return new KomootImportExecutionResponse(
|
||||||
existingActivity.getId(),
|
existingActivity.getId(),
|
||||||
request.activityId(),
|
request.getActivityId(),
|
||||||
"SKIPPED_ALREADY_IMPORTED",
|
"SKIPPED_ALREADY_IMPORTED",
|
||||||
"Komoot activity " + request.activityId() + " was already imported."
|
"Komoot activity " + request.getActivityId() + " was already imported."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode details = fetchActivityDetails(request.email(), request.password(), request.activityId());
|
JsonNode details = fetchActivityDetails(request.getEmail(), request.getPassword(), request.getActivityId());
|
||||||
pauseBetweenDetailAndGpxRequest();
|
pauseBetweenDetailAndGpxRequest();
|
||||||
byte[] gpxData = fetchActivityGpx(request.email(), request.password(), request.activityId());
|
byte[] gpxData = fetchActivityGpx(request.getEmail(), request.getPassword(), request.getActivityId());
|
||||||
|
|
||||||
ByteArrayMultipartFile gpxFile = new ByteArrayMultipartFile(
|
ByteArrayMultipartFile gpxFile = new ByteArrayMultipartFile(
|
||||||
"file",
|
"file",
|
||||||
"komoot-" + request.activityId() + ".gpx",
|
"komoot-" + request.getActivityId() + ".gpx",
|
||||||
"application/gpx+xml",
|
"application/gpx+xml",
|
||||||
gpxData
|
gpxData
|
||||||
);
|
);
|
||||||
|
|
||||||
Activity.Visibility mappedVisibility = mapVisibility(nullableText(details, "status"));
|
Activity.Visibility mappedVisibility = mapVisibility(nullableText(details, "status"));
|
||||||
String mappedTitle = firstNonBlank(nullableText(details, "name"), null, "Komoot Activity " + request.activityId());
|
String mappedTitle = firstNonBlank(nullableText(details, "name"), null, "Komoot Activity " + request.getActivityId());
|
||||||
String mappedDescription = nullableText(details, "description");
|
String mappedDescription = nullableText(details, "description");
|
||||||
Activity.ActivityType mappedActivityType = mapKomootSportToActivityType(nullableText(details, "sport"));
|
Activity.ActivityType mappedActivityType = mapKomootSportToActivityType(nullableText(details, "sport"));
|
||||||
|
|
||||||
|
|
@ -156,7 +156,7 @@ public class KomootImportService {
|
||||||
mappedVisibility
|
mappedVisibility
|
||||||
);
|
);
|
||||||
|
|
||||||
importedActivity.setKomootActivityId(request.activityId());
|
importedActivity.setKomootActivityId(request.getActivityId());
|
||||||
importedActivity.setTitle(mappedTitle);
|
importedActivity.setTitle(mappedTitle);
|
||||||
importedActivity.setDescription(mappedDescription);
|
importedActivity.setDescription(mappedDescription);
|
||||||
importedActivity.setVisibility(mappedVisibility);
|
importedActivity.setVisibility(mappedVisibility);
|
||||||
|
|
@ -167,7 +167,7 @@ public class KomootImportService {
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"Imported Komoot activity {} into FitPub activity {} with visibility {} and type {}",
|
"Imported Komoot activity {} into FitPub activity {} with visibility {} and type {}",
|
||||||
request.activityId(),
|
request.getActivityId(),
|
||||||
importedActivity.getId(),
|
importedActivity.getId(),
|
||||||
importedActivity.getVisibility(),
|
importedActivity.getVisibility(),
|
||||||
importedActivity.getActivityType()
|
importedActivity.getActivityType()
|
||||||
|
|
@ -177,9 +177,9 @@ public class KomootImportService {
|
||||||
|
|
||||||
return new KomootImportExecutionResponse(
|
return new KomootImportExecutionResponse(
|
||||||
importedActivity.getId(),
|
importedActivity.getId(),
|
||||||
request.activityId(),
|
request.getActivityId(),
|
||||||
"IMPORTED",
|
"IMPORTED",
|
||||||
"Imported Komoot activity " + request.activityId() + " into FitPub activity " + importedActivity.getId()
|
"Imported Komoot activity " + request.getActivityId() + " into FitPub activity " + importedActivity.getId()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,15 +193,15 @@ public class KomootImportService {
|
||||||
|
|
||||||
private URI buildInitialUri(KomootImportRequest request) {
|
private URI buildInitialUri(KomootImportRequest request) {
|
||||||
String normalizedBaseUrl = komootBaseUrl.endsWith("/") ? komootBaseUrl.substring(0, komootBaseUrl.length() - 1) : komootBaseUrl;
|
String normalizedBaseUrl = komootBaseUrl.endsWith("/") ? komootBaseUrl.substring(0, komootBaseUrl.length() - 1) : komootBaseUrl;
|
||||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(normalizedBaseUrl + "/api/v007/users/" + request.userId() + "/tours/")
|
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(normalizedBaseUrl + "/api/v007/users/" + request.getUserId() + "/tours/")
|
||||||
.queryParam("type", "tour_recorded")
|
.queryParam("type", "tour_recorded")
|
||||||
.queryParam("sort_field", "date")
|
.queryParam("sort_field", "date")
|
||||||
.queryParam("sort_direction", "desc")
|
.queryParam("sort_direction", "desc")
|
||||||
.queryParam("limit", PAGE_SIZE);
|
.queryParam("limit", PAGE_SIZE);
|
||||||
|
|
||||||
if (request.startDate() != null && request.endDate() != null) {
|
if (request.getStartDate() != null && request.getEndDate() != null) {
|
||||||
builder.queryParam("start_date", formatKomootStartDate(request.startDate()))
|
builder.queryParam("start_date", formatKomootStartDate(request.getStartDate()))
|
||||||
.queryParam("end_date", formatKomootEndDate(request.endDate()));
|
.queryParam("end_date", formatKomootEndDate(request.getEndDate()));
|
||||||
} else {
|
} else {
|
||||||
builder.queryParam("status", "private")
|
builder.queryParam("status", "private")
|
||||||
.queryParam("name", "")
|
.queryParam("name", "")
|
||||||
|
|
|
||||||
|
|
@ -154,15 +154,15 @@ class KomootImportServiceTest {
|
||||||
new KomootImportRequest("user@example.com", "secret", "123456", null, null),
|
new KomootImportRequest("user@example.com", "secret", "123456", null, null),
|
||||||
userId);
|
userId);
|
||||||
|
|
||||||
assertThat(response.totalCount()).isEqualTo(2);
|
assertThat(response.getTotalCount()).isEqualTo(2);
|
||||||
assertThat(response.activities()).hasSize(2);
|
assertThat(response.getActivities()).hasSize(2);
|
||||||
assertThat(response.activities().get(0).id()).isEqualTo(1001L);
|
assertThat(response.getActivities().get(0).getId()).isEqualTo(1001L);
|
||||||
assertThat(response.activities().get(0).imported()).isFalse();
|
assertThat(response.getActivities().get(0).isImported()).isFalse();
|
||||||
assertThat(response.activities().get(0).fitPubActivityId()).isNull();
|
assertThat(response.getActivities().get(0).getFitPubActivityId()).isNull();
|
||||||
assertThat(response.activities().get(0).timeInMotionSeconds()).isEqualTo(7800);
|
assertThat(response.getActivities().get(0).getTimeInMotionSeconds()).isEqualTo(7800);
|
||||||
assertThat(response.activities().get(1).name()).isEqualTo("Lunch Walk");
|
assertThat(response.getActivities().get(1).getName()).isEqualTo("Lunch Walk");
|
||||||
assertThat(response.activities().get(1).imported()).isTrue();
|
assertThat(response.getActivities().get(1).isImported()).isTrue();
|
||||||
assertThat(response.activities().get(1).fitPubActivityId()).isEqualTo(existingActivityId);
|
assertThat(response.getActivities().get(1).getFitPubActivityId()).isEqualTo(existingActivityId);
|
||||||
|
|
||||||
verify(throttledService).pauseBeforeNextPageRequest();
|
verify(throttledService).pauseBeforeNextPageRequest();
|
||||||
server.verify();
|
server.verify();
|
||||||
|
|
@ -219,11 +219,11 @@ class KomootImportServiceTest {
|
||||||
),
|
),
|
||||||
userId);
|
userId);
|
||||||
|
|
||||||
assertThat(response.totalCount()).isEqualTo(2);
|
assertThat(response.getTotalCount()).isEqualTo(2);
|
||||||
assertThat(response.activities()).extracting("id").containsExactly(1002L, 1003L);
|
assertThat(response.getActivities()).extracting("id").containsExactly(1002L, 1003L);
|
||||||
assertThat(response.activities().get(0).imported()).isFalse();
|
assertThat(response.getActivities().get(0).isImported()).isFalse();
|
||||||
assertThat(response.activities().get(1).imported()).isTrue();
|
assertThat(response.getActivities().get(1).isImported()).isTrue();
|
||||||
assertThat(response.activities().get(1).fitPubActivityId()).isEqualTo(existingActivityId);
|
assertThat(response.getActivities().get(1).getFitPubActivityId()).isEqualTo(existingActivityId);
|
||||||
|
|
||||||
server.verify();
|
server.verify();
|
||||||
}
|
}
|
||||||
|
|
@ -296,9 +296,9 @@ class KomootImportServiceTest {
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
|
|
||||||
assertThat(response.importedActivityId()).isEqualTo(importedActivityId);
|
assertThat(response.getImportedActivityId()).isEqualTo(importedActivityId);
|
||||||
assertThat(response.importedKomootActivityId()).isEqualTo(2880957035L);
|
assertThat(response.getImportedKomootActivityId()).isEqualTo(2880957035L);
|
||||||
assertThat(response.status()).isEqualTo("IMPORTED");
|
assertThat(response.getStatus()).isEqualTo("IMPORTED");
|
||||||
assertThat(importedActivity.getKomootActivityId()).isEqualTo(2880957035L);
|
assertThat(importedActivity.getKomootActivityId()).isEqualTo(2880957035L);
|
||||||
assertThat(importedActivity.getTitle()).isEqualTo("Latest Ride");
|
assertThat(importedActivity.getTitle()).isEqualTo("Latest Ride");
|
||||||
assertThat(importedActivity.getDescription()).isEqualTo("Imported from Komoot");
|
assertThat(importedActivity.getDescription()).isEqualTo("Imported from Komoot");
|
||||||
|
|
@ -326,9 +326,9 @@ class KomootImportServiceTest {
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
|
|
||||||
assertThat(response.importedActivityId()).isEqualTo(existingActivityId);
|
assertThat(response.getImportedActivityId()).isEqualTo(existingActivityId);
|
||||||
assertThat(response.importedKomootActivityId()).isEqualTo(3002L);
|
assertThat(response.getImportedKomootActivityId()).isEqualTo(3002L);
|
||||||
assertThat(response.status()).isEqualTo("SKIPPED_ALREADY_IMPORTED");
|
assertThat(response.getStatus()).isEqualTo("SKIPPED_ALREADY_IMPORTED");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -386,8 +386,8 @@ class KomootImportServiceTest {
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
|
|
||||||
assertThat(response.importedActivityId()).isEqualTo(importedActivityId);
|
assertThat(response.getImportedActivityId()).isEqualTo(importedActivityId);
|
||||||
assertThat(response.status()).isEqualTo("IMPORTED");
|
assertThat(response.getStatus()).isEqualTo("IMPORTED");
|
||||||
assertThat(importedActivity.getActivityType()).isEqualTo(Activity.ActivityType.OTHER);
|
assertThat(importedActivity.getActivityType()).isEqualTo(Activity.ActivityType.OTHER);
|
||||||
|
|
||||||
verify(throttledService).pauseBetweenDetailAndGpxRequest();
|
verify(throttledService).pauseBetweenDetailAndGpxRequest();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue
DTOs in this PR are all records. While I generally like them, I'd prefer the DTO to mimic the existing ones, classes with Lomboks
@Dataannotation. If the DTOs switch to records, it should be done for all, not fragmented