refactor(komoot): gate Komoot integration behind feature flag
Signed-off-by: Marcus Fihlon <marcus@fihlon.swiss>
This commit is contained in:
parent
0663ca407f
commit
98be2cfada
7 changed files with 107 additions and 1 deletions
|
|
@ -0,0 +1,21 @@
|
||||||
|
package net.javahippie.fitpub.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Central support flag for Komoot integration availability.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class KomootSupport {
|
||||||
|
|
||||||
|
private final boolean enabled;
|
||||||
|
|
||||||
|
public KomootSupport(@Value("${fitpub.komoot.enabled:false}") boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package net.javahippie.fitpub.controller;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.javahippie.fitpub.config.KomootSupport;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes global model attributes required by shared layouts.
|
||||||
|
*/
|
||||||
|
@ControllerAdvice
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GlobalModelAttributes {
|
||||||
|
|
||||||
|
private final KomootSupport komootSupport;
|
||||||
|
|
||||||
|
@ModelAttribute("komootSupportEnabled")
|
||||||
|
public boolean komootSupportEnabled() {
|
||||||
|
return komootSupport.isEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package net.javahippie.fitpub.controller;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.javahippie.fitpub.config.KomootSupport;
|
||||||
import net.javahippie.fitpub.model.dto.KomootActivityImportRequest;
|
import net.javahippie.fitpub.model.dto.KomootActivityImportRequest;
|
||||||
import net.javahippie.fitpub.model.dto.KomootActivitiesResponse;
|
import net.javahippie.fitpub.model.dto.KomootActivitiesResponse;
|
||||||
import net.javahippie.fitpub.model.dto.KomootImportExecutionResponse;
|
import net.javahippie.fitpub.model.dto.KomootImportExecutionResponse;
|
||||||
|
|
@ -30,6 +31,7 @@ import java.util.UUID;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class KomootImportController {
|
public class KomootImportController {
|
||||||
|
|
||||||
|
private final KomootSupport komootSupport;
|
||||||
private final KomootImportService komootImportService;
|
private final KomootImportService komootImportService;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
|
@ -38,6 +40,8 @@ public class KomootImportController {
|
||||||
@Valid @RequestBody KomootImportRequest request,
|
@Valid @RequestBody KomootImportRequest request,
|
||||||
Authentication authentication
|
Authentication authentication
|
||||||
) {
|
) {
|
||||||
|
ensureKomootSupportEnabled();
|
||||||
|
|
||||||
UUID fitPubUserId = userRepository.findByUsername(authentication.getName())
|
UUID fitPubUserId = userRepository.findByUsername(authentication.getName())
|
||||||
.orElseThrow(() -> new IllegalArgumentException("Authenticated user not found"))
|
.orElseThrow(() -> new IllegalArgumentException("Authenticated user not found"))
|
||||||
.getId();
|
.getId();
|
||||||
|
|
@ -53,6 +57,8 @@ public class KomootImportController {
|
||||||
@Valid @RequestBody KomootActivityImportRequest request,
|
@Valid @RequestBody KomootActivityImportRequest request,
|
||||||
Authentication authentication
|
Authentication authentication
|
||||||
) {
|
) {
|
||||||
|
ensureKomootSupportEnabled();
|
||||||
|
|
||||||
UUID fitPubUserId = userRepository.findByUsername(authentication.getName())
|
UUID fitPubUserId = userRepository.findByUsername(authentication.getName())
|
||||||
.orElseThrow(() -> new IllegalArgumentException("Authenticated user not found"))
|
.orElseThrow(() -> new IllegalArgumentException("Authenticated user not found"))
|
||||||
.getId();
|
.getId();
|
||||||
|
|
@ -67,6 +73,12 @@ public class KomootImportController {
|
||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensureKomootSupportEnabled() {
|
||||||
|
if (!komootSupport.isEnabled()) {
|
||||||
|
throw new KomootSupportDisabledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(IllegalArgumentException.class)
|
@ExceptionHandler(IllegalArgumentException.class)
|
||||||
public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e) {
|
public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e) {
|
||||||
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
|
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
|
||||||
|
|
@ -86,5 +98,13 @@ public class KomootImportController {
|
||||||
return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(new ErrorResponse(e.getMessage()));
|
return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(new ErrorResponse(e.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
record ErrorResponse(String error) {}
|
@ExceptionHandler(KomootSupportDisabledException.class)
|
||||||
|
public ResponseEntity<ErrorResponse> handleKomootSupportDisabled(KomootSupportDisabledException e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Komoot support is disabled."));
|
||||||
|
}
|
||||||
|
|
||||||
|
record ErrorResponse(String error) {}
|
||||||
|
|
||||||
|
static class KomootSupportDisabledException extends RuntimeException {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package net.javahippie.fitpub.controller;
|
package net.javahippie.fitpub.controller;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.javahippie.fitpub.config.KomootSupport;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
@ -10,10 +12,21 @@ import java.time.LocalDate;
|
||||||
* Serves the Komoot import preview page.
|
* Serves the Komoot import preview page.
|
||||||
*/
|
*/
|
||||||
@Controller
|
@Controller
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class KomootImportViewController {
|
public class KomootImportViewController {
|
||||||
|
|
||||||
|
private final KomootSupport komootSupport;
|
||||||
|
|
||||||
@GetMapping("/komoot-import")
|
@GetMapping("/komoot-import")
|
||||||
public String komootImportPage(Model model) {
|
public String komootImportPage(Model model) {
|
||||||
|
if (!komootSupport.isEnabled()) {
|
||||||
|
model.addAttribute("pageTitle", "Komoot Import Unavailable");
|
||||||
|
model.addAttribute("featureName", "Komoot Import");
|
||||||
|
model.addAttribute("featureMessage", "Komoot support is currently disabled on this instance.");
|
||||||
|
model.addAttribute("featureIcon", "bi bi-signpost-split text-secondary");
|
||||||
|
return "feature-disabled";
|
||||||
|
}
|
||||||
|
|
||||||
LocalDate today = LocalDate.now();
|
LocalDate today = LocalDate.now();
|
||||||
model.addAttribute("pageTitle", "Komoot Import");
|
model.addAttribute("pageTitle", "Komoot Import");
|
||||||
model.addAttribute("defaultStartDate", today.withDayOfYear(1));
|
model.addAttribute("defaultStartDate", today.withDayOfYear(1));
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,9 @@ fitpub:
|
||||||
enabled: ${WEATHER_ENABLED:false}
|
enabled: ${WEATHER_ENABLED:false}
|
||||||
api-key: ${OPENWEATHERMAP_API_KEY:}
|
api-key: ${OPENWEATHERMAP_API_KEY:}
|
||||||
|
|
||||||
|
# Komoot settings
|
||||||
komoot:
|
komoot:
|
||||||
|
enabled: ${KOMOOT_ENABLED:false}
|
||||||
base-url: ${KOMOOT_BASE_URL:https://www.komoot.com}
|
base-url: ${KOMOOT_BASE_URL:https://www.komoot.com}
|
||||||
paginated-request-delay-ms: ${KOMOOT_PAGINATED_REQUEST_DELAY_MS:1000}
|
paginated-request-delay-ms: ${KOMOOT_PAGINATED_REQUEST_DELAY_MS:1000}
|
||||||
detail-to-gpx-delay-ms: ${KOMOOT_DETAIL_TO_GPX_DELAY_MS:500}
|
detail-to-gpx-delay-ms: ${KOMOOT_DETAIL_TO_GPX_DELAY_MS:500}
|
||||||
|
|
|
||||||
29
src/main/resources/templates/feature-disabled.html
Normal file
29
src/main/resources/templates/feature-disabled.html
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{layout}">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title th:text="${pageTitle}">Feature Unavailable</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h2 class="mb-3">
|
||||||
|
<i th:class="${featureIcon != null ? featureIcon : 'bi bi-slash-circle text-secondary'}"></i>
|
||||||
|
<span th:text="${featureName != null ? featureName : 'Feature'}">Feature</span>
|
||||||
|
</h2>
|
||||||
|
<p class="text-muted mb-0"
|
||||||
|
th:text="${featureMessage != null ? featureMessage : 'This feature is currently unavailable on this FitPub instance.'}">
|
||||||
|
This feature is currently unavailable on this FitPub instance.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -97,7 +97,7 @@
|
||||||
<i class="bi bi-file-earmark-zip"></i> Batch Import
|
<i class="bi bi-file-earmark-zip"></i> Batch Import
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li th:if="${komootSupportEnabled}">
|
||||||
<a class="dropdown-item" th:href="@{/komoot-import}">
|
<a class="dropdown-item" th:href="@{/komoot-import}">
|
||||||
<i class="bi bi-signpost-split"></i> Komoot Import
|
<i class="bi bi-signpost-split"></i> Komoot Import
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue