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 lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.javahippie.fitpub.config.KomootSupport;
|
||||
import net.javahippie.fitpub.model.dto.KomootActivityImportRequest;
|
||||
import net.javahippie.fitpub.model.dto.KomootActivitiesResponse;
|
||||
import net.javahippie.fitpub.model.dto.KomootImportExecutionResponse;
|
||||
|
|
@ -30,6 +31,7 @@ import java.util.UUID;
|
|||
@Slf4j
|
||||
public class KomootImportController {
|
||||
|
||||
private final KomootSupport komootSupport;
|
||||
private final KomootImportService komootImportService;
|
||||
private final UserRepository userRepository;
|
||||
|
||||
|
|
@ -38,6 +40,8 @@ public class KomootImportController {
|
|||
@Valid @RequestBody KomootImportRequest request,
|
||||
Authentication authentication
|
||||
) {
|
||||
ensureKomootSupportEnabled();
|
||||
|
||||
UUID fitPubUserId = userRepository.findByUsername(authentication.getName())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Authenticated user not found"))
|
||||
.getId();
|
||||
|
|
@ -53,6 +57,8 @@ public class KomootImportController {
|
|||
@Valid @RequestBody KomootActivityImportRequest request,
|
||||
Authentication authentication
|
||||
) {
|
||||
ensureKomootSupportEnabled();
|
||||
|
||||
UUID fitPubUserId = userRepository.findByUsername(authentication.getName())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Authenticated user not found"))
|
||||
.getId();
|
||||
|
|
@ -67,6 +73,12 @@ public class KomootImportController {
|
|||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
private void ensureKomootSupportEnabled() {
|
||||
if (!komootSupport.isEnabled()) {
|
||||
throw new KomootSupportDisabledException();
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e) {
|
||||
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()));
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.javahippie.fitpub.config.KomootSupport;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
|
@ -10,10 +12,21 @@ import java.time.LocalDate;
|
|||
* Serves the Komoot import preview page.
|
||||
*/
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
public class KomootImportViewController {
|
||||
|
||||
private final KomootSupport komootSupport;
|
||||
|
||||
@GetMapping("/komoot-import")
|
||||
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();
|
||||
model.addAttribute("pageTitle", "Komoot Import");
|
||||
model.addAttribute("defaultStartDate", today.withDayOfYear(1));
|
||||
|
|
|
|||
|
|
@ -104,7 +104,9 @@ fitpub:
|
|||
enabled: ${WEATHER_ENABLED:false}
|
||||
api-key: ${OPENWEATHERMAP_API_KEY:}
|
||||
|
||||
# Komoot settings
|
||||
komoot:
|
||||
enabled: ${KOMOOT_ENABLED:false}
|
||||
base-url: ${KOMOOT_BASE_URL:https://www.komoot.com}
|
||||
paginated-request-delay-ms: ${KOMOOT_PAGINATED_REQUEST_DELAY_MS:1000}
|
||||
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
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<li th:if="${komootSupportEnabled}">
|
||||
<a class="dropdown-item" th:href="@{/komoot-import}">
|
||||
<i class="bi bi-signpost-split"></i> Komoot Import
|
||||
</a>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue