From d47daa6dfc8b757720ac89971a71e10b9339361e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Z=C3=B6ller?= Date: Tue, 2 Dec 2025 22:01:27 +0100 Subject: [PATCH] Show public activities to everrybody --- .../fitpub/config/SecurityConfig.java | 10 ++++-- .../fitpub/controller/ActivityController.java | 31 ++++++++++++++++--- .../templates/activities/detail.html | 6 +++- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/operaton/fitpub/config/SecurityConfig.java b/src/main/java/org/operaton/fitpub/config/SecurityConfig.java index 2486a02..b7afd92 100644 --- a/src/main/java/org/operaton/fitpub/config/SecurityConfig.java +++ b/src/main/java/org/operaton/fitpub/config/SecurityConfig.java @@ -71,6 +71,9 @@ public class SecurityConfig { // Public endpoints - Timeline API (read-only) .requestMatchers(HttpMethod.GET, "/api/timeline/public").permitAll() + // Public endpoints - Individual activity details (GET only, for public activities) + .requestMatchers(HttpMethod.GET, "/api/activities/*").permitAll() + // Public endpoints - Activity track data (for public activities) .requestMatchers(HttpMethod.GET, "/api/activities/*/track").permitAll() @@ -90,8 +93,11 @@ public class SecurityConfig { .requestMatchers(HttpMethod.POST, "/api/activities/*/comments").authenticated() .requestMatchers(HttpMethod.DELETE, "/api/activities/*/comments/*").authenticated() - // Protected endpoints - Activities API - .requestMatchers("/api/activities/**").authenticated() + // Protected endpoints - Activities API (upload, edit, delete) + .requestMatchers(HttpMethod.POST, "/api/activities/upload").authenticated() + .requestMatchers(HttpMethod.PUT, "/api/activities/*").authenticated() + .requestMatchers(HttpMethod.DELETE, "/api/activities/*").authenticated() + .requestMatchers(HttpMethod.GET, "/api/activities").authenticated() // List of user's own activities // Protected endpoints - Timeline API (user-specific) .requestMatchers("/api/timeline/**").authenticated() diff --git a/src/main/java/org/operaton/fitpub/controller/ActivityController.java b/src/main/java/org/operaton/fitpub/controller/ActivityController.java index a552d35..48da28a 100644 --- a/src/main/java/org/operaton/fitpub/controller/ActivityController.java +++ b/src/main/java/org/operaton/fitpub/controller/ActivityController.java @@ -208,9 +208,11 @@ public class ActivityController { /** * Retrieves an activity by ID. + * Public activities can be viewed without authentication. + * Non-public activities require authentication and ownership/follower access. * * @param id the activity ID - * @param userDetails the authenticated user + * @param userDetails the authenticated user (optional) * @return the activity */ @GetMapping("/{id}") @@ -218,14 +220,33 @@ public class ActivityController { @PathVariable UUID id, @AuthenticationPrincipal UserDetails userDetails ) { - UUID userId = getUserId(userDetails); - - Activity activity = fitFileService.getActivity(id, userId); + // First try to get the activity directly + Activity activity = fitFileService.getActivityById(id); if (activity == null) { return ResponseEntity.notFound().build(); } - ActivityDTO dto = ActivityDTO.fromEntity(activity); + // Check visibility + if (activity.getVisibility() == Activity.Visibility.PUBLIC) { + // Public activities are always accessible + ActivityDTO dto = ActivityDTO.fromEntity(activity); + return ResponseEntity.ok(dto); + } + + // For non-public activities, require authentication + if (userDetails == null) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + UUID userId = getUserId(userDetails); + + // Check if user has access (owner or follower) + Activity checkedActivity = fitFileService.getActivity(id, userId); + if (checkedActivity == null) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + ActivityDTO dto = ActivityDTO.fromEntity(checkedActivity); return ResponseEntity.ok(dto); } diff --git a/src/main/resources/templates/activities/detail.html b/src/main/resources/templates/activities/detail.html index 9a9802b..8ca2b59 100644 --- a/src/main/resources/templates/activities/detail.html +++ b/src/main/resources/templates/activities/detail.html @@ -595,12 +595,16 @@ // Setup like button click handler document.getElementById('likeBtn').addEventListener('click', handleLikeClick); + // Show comment form for authenticated users + document.getElementById('commentForm').style.display = 'block'; + // Setup comment form submit handler document.getElementById('addCommentForm').addEventListener('submit', handleCommentSubmit); } else { // Show login prompt for non-authenticated users document.getElementById('loginPrompt').style.display = 'block'; - document.getElementById('likeBtn').disabled = true; + // Hide like button for non-authenticated users + document.getElementById('likeBtn').style.display = 'none'; } }