diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx
index 34f2113..4be7738 100644
--- a/frontend/src/components/Dropdown.tsx
+++ b/frontend/src/components/Dropdown.tsx
@@ -9,7 +9,9 @@ type DropdownItemProps = {
const DropdownItem = ({ item, onClick, className }: DropdownItemProps) => {
return (
-
onClick(item)}>
+ onClick(item)}
+ >
{item}
);
@@ -30,7 +32,7 @@ const Dropdown = ({ label, children, className }: DropdownProps) => {
};
useEffect(() => {
- function handleClickOutside(event: { target: any; }) {
+ function handleClickOutside(event: { target: any }) {
if (ref.current && !ref.current.contains(event.target)) {
setIsOpen(false);
}
diff --git a/src/main/java/com/ddf/vodsystem/controllers/ClipController.java b/src/main/java/com/ddf/vodsystem/controllers/ClipController.java
index e340c8d..7f5b506 100644
--- a/src/main/java/com/ddf/vodsystem/controllers/ClipController.java
+++ b/src/main/java/com/ddf/vodsystem/controllers/ClipController.java
@@ -11,6 +11,7 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.*;
import java.util.List;
+import java.util.Optional;
@RestController
@RequestMapping("/api/v1/clips")
@@ -35,12 +36,12 @@ public class ClipController {
@GetMapping("/{id}")
public ResponseEntity> getClipById(@PathVariable Long id) {
- Clip clip = clipService.getClipById(id);
- if (clip == null) {
+ Optional clip = clipService.getClipById(id);
+ if (clip.isEmpty()) {
return ResponseEntity.notFound().build();
}
- ClipDTO clipDTO = convertToDTO(clip);
+ ClipDTO clipDTO = convertToDTO(clip.get());
return ResponseEntity.ok(
new APIResponse<>("success", "Clip retrieved successfully", clipDTO)
diff --git a/src/main/java/com/ddf/vodsystem/controllers/UserController.java b/src/main/java/com/ddf/vodsystem/controllers/UserController.java
index 9a095c7..b01ed53 100644
--- a/src/main/java/com/ddf/vodsystem/controllers/UserController.java
+++ b/src/main/java/com/ddf/vodsystem/controllers/UserController.java
@@ -10,6 +10,8 @@ import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
+import java.util.Optional;
+
@RestController
@RequestMapping("/api/v1/auth/")
public class UserController {
@@ -21,14 +23,14 @@ public class UserController {
@GetMapping("/user")
public ResponseEntity> user() {
- User user = userService.getLoggedInUser();
+ Optional user = userService.getLoggedInUser();
- if (user == null) {
+ if (user.isEmpty()) {
throw new NotAuthenticated("User not authenticated");
}
return ResponseEntity.ok(
- new APIResponse<>("success", "User retrieved successfully", user)
+ new APIResponse<>("success", "User retrieved successfully", user.get())
);
}
diff --git a/src/main/java/com/ddf/vodsystem/security/JwtFilter.java b/src/main/java/com/ddf/vodsystem/security/JwtFilter.java
index 6c4e72f..1af18e2 100644
--- a/src/main/java/com/ddf/vodsystem/security/JwtFilter.java
+++ b/src/main/java/com/ddf/vodsystem/security/JwtFilter.java
@@ -1,7 +1,6 @@
package com.ddf.vodsystem.security;
import com.ddf.vodsystem.entities.User;
-import com.ddf.vodsystem.exceptions.NotAuthenticated;
import com.ddf.vodsystem.services.UserService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
@@ -20,6 +19,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
@Component
public class JwtFilter extends OncePerRequestFilter {
@@ -59,32 +59,34 @@ public class JwtFilter extends OncePerRequestFilter {
}
}
- if (jwt == null) {
- logger.debug("No JWT found in request");
- filterChain.doFilter(request, response);
- return;
- }
-
- logger.debug("JWT found in request");
- Long userId = jwtService.validateTokenAndGetUserId(jwt);
-
- if (userId == null) {
- logger.warn("Invalid JWT: {}", jwt);
- filterChain.doFilter(request, response);
- return;
- }
-
- User user;
- try {
- user = userService.getUserById(userId);
- } catch (NotAuthenticated e) {
- filterChain.doFilter(request, response);
- return;
- }
-
- Authentication authentication = new UsernamePasswordAuthenticationToken(user, jwt, List.of(new SimpleGrantedAuthority("ROLE_USER")));
- SecurityContextHolder.getContext().setAuthentication(authentication);
-
+ Optional authentication = getAuthentication(jwt);
+ authentication.ifPresent(value ->
+ SecurityContextHolder.getContext().setAuthentication(value)
+ );
filterChain.doFilter(request, response);
}
+
+ private Optional getAuthentication(String jwt) {
+ if (jwt == null || jwt.isEmpty()) {
+ return Optional.empty();
+ }
+
+ Long userId = jwtService.validateTokenAndGetUserId(jwt);
+ if (userId == null) {
+ return Optional.empty();
+ }
+
+ Optional user = userService.getUserById(userId);
+ if (user.isEmpty()) {
+ return Optional.empty();
+ }
+
+ Authentication authentication = new UsernamePasswordAuthenticationToken(
+ user.get(),
+ jwt,
+ List.of(new SimpleGrantedAuthority("ROLE_USER"))
+ );
+
+ return Optional.of(authentication);
+ }
}
diff --git a/src/main/java/com/ddf/vodsystem/services/ClipService.java b/src/main/java/com/ddf/vodsystem/services/ClipService.java
index d49ea2b..b8c8700 100644
--- a/src/main/java/com/ddf/vodsystem/services/ClipService.java
+++ b/src/main/java/com/ddf/vodsystem/services/ClipService.java
@@ -8,6 +8,7 @@ import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.ExecutionException;
import com.ddf.vodsystem.exceptions.FFMPEGException;
@@ -60,42 +61,56 @@ public class ClipService {
* @throws InterruptedException if the thread is interrupted during processing.
*/
public void create(VideoMetadata inputMetadata,
- VideoMetadata outputMetadata,
- File inputFile,
- File outputFile,
- ProgressTracker progress)
+ VideoMetadata outputMetadata,
+ File inputFile,
+ File outputFile,
+ ProgressTracker progress)
throws IOException, InterruptedException {
- User user = userService.getLoggedInUser();
+ Optional user = userService.getLoggedInUser();
metadataService.normalizeVideoMetadata(inputMetadata, outputMetadata);
compressionService.compress(inputFile, outputFile, outputMetadata, progress)
- .thenRun(() -> {
- if (user != null) {
- persistClip(outputMetadata, user, outputFile, inputFile.getName());
- }
- });
+ .thenRun(() -> user.ifPresent(value ->
+ persistClip(
+ outputMetadata,
+ value,
+ outputFile,
+ inputFile.getName()
+ )));
}
+ /**
+ * Retrieves all clips associated with the currently logged-in user.
+ *
+ * @return a list of clips belonging to the authenticated user.
+ * @throws NotAuthenticated if the user is not authenticated.
+ */
public List getClipsByUser() {
- User user = userService.getLoggedInUser();
+ Optional user = userService.getLoggedInUser();
- if (user == null) {
- logger.warn("No authenticated user found");
- return List.of();
+ if (user.isEmpty()) {
+ throw new NotAuthenticated("User is not authenticated");
}
- return clipRepository.findByUser(user);
+ return clipRepository.findByUser(user.get());
}
- public Clip getClipById(Long id) {
- Clip clip = clipRepository.findById(id).orElse(null);
+ /**
+ * Retrieves a clip by its ID, ensuring the user is authenticated to access it.
+ *
+ * @param id the ID of the clip to retrieve.
+ * @return an Optional containing the Clip if found and accessible, or empty if not found.
+ * @throws NotAuthenticated if the user is not authorized to access the clip.
+ */
+ public Optional getClipById(Long id) {
+ Optional clip = clipRepository.findById(id);
- if (clip == null) {
+ if (clip.isEmpty()) {
logger.warn("Clip with ID {} not found", id);
- return null;
+ return clip;
}
- if (!isAuthenticatedForClip(clip)) {
+ if (!isAuthenticatedForClip(clip.get())) {
logger.warn("User is not authorized to access clip with ID {}", id);
throw new NotAuthenticated("You are not authorized to access this clip");
}
@@ -103,34 +118,44 @@ public class ClipService {
return clip;
}
+ /**
+ * Deletes a clip by its ID, ensuring the user is authenticated to perform the deletion.
+ *
+ * @param id the ID of the clip to delete.
+ * @return true if the clip was successfully deleted, false if it was not found.
+ * @throws NotAuthenticated if the user is not authorized to delete the clip.
+ */
public boolean deleteClip(Long id) {
- Clip clip = getClipById(id);
- if (clip == null) {
+ Optional possibleClip = getClipById(id);
+ if (possibleClip.isEmpty()) {
logger.warn("Clip with ID {} not found for deletion", id);
return false;
}
+ Clip clip = possibleClip.get();
if (!isAuthenticatedForClip(clip)) {
- logger.warn("User is not authorized to delete clip with ID {}", id);
throw new NotAuthenticated("You are not authorized to delete this clip");
}
- File clipFile = new File(clip.getVideoPath());
- File thumbnailFile = new File(clip.getThumbnailPath());
- directoryService.deleteFile(clipFile);
- directoryService.deleteFile(thumbnailFile);
-
+ deleteClipFiles(clip);
clipRepository.delete(clip);
+
logger.info("Clip with ID {} deleted successfully", id);
return true;
}
+ /**
+ * Checks if the currently logged-in user is authenticated to access the specified clip.
+ *
+ * @param clip the clip to check access for.
+ * @return true if the user is authenticated for the clip, false otherwise.
+ */
public boolean isAuthenticatedForClip(Clip clip) {
- User user = userService.getLoggedInUser();
- if (user == null || clip == null) {
+ Optional user = userService.getLoggedInUser();
+ if (user.isEmpty() || clip == null) {
return false;
}
- return user.getId().equals(clip.getUser().getId());
+ return user.get().getId().equals(clip.getUser().getId());
}
private void persistClip(VideoMetadata videoMetadata,
@@ -175,4 +200,20 @@ public class ClipService {
logger.info("Clip created successfully with ID: {}", clip.getId());
}
+
+ private void deleteClipFiles(Clip clip) {
+ File clipFile = new File(clip.getVideoPath());
+ File thumbnailFile = new File(clip.getThumbnailPath());
+
+ boolean clipDeleted = directoryService.deleteFile(clipFile);
+ boolean thumbnailDeleted = directoryService.deleteFile(thumbnailFile);
+
+ if (!clipDeleted) {
+ throw new FFMPEGException("Failed to delete clip file: " + clipFile.getAbsolutePath());
+ }
+
+ if (!thumbnailDeleted) {
+ throw new FFMPEGException("Failed to delete thumbnail file: " + thumbnailFile.getAbsolutePath());
+ }
+ }
}
diff --git a/src/main/java/com/ddf/vodsystem/services/DirectoryService.java b/src/main/java/com/ddf/vodsystem/services/DirectoryService.java
index 64252c5..2b23515 100644
--- a/src/main/java/com/ddf/vodsystem/services/DirectoryService.java
+++ b/src/main/java/com/ddf/vodsystem/services/DirectoryService.java
@@ -118,7 +118,7 @@ public class DirectoryService {
try {
Files.delete(file.toPath());
- logger.info("Deleted file: {}", file.getAbsolutePath());
+ logger.debug("Deleted file: {}", file.getAbsolutePath());
return true;
} catch (IOException e) {
logger.error("Error deleting file: {}", e.getMessage());
diff --git a/src/main/java/com/ddf/vodsystem/services/UserService.java b/src/main/java/com/ddf/vodsystem/services/UserService.java
index 7dc2032..5c63d80 100644
--- a/src/main/java/com/ddf/vodsystem/services/UserService.java
+++ b/src/main/java/com/ddf/vodsystem/services/UserService.java
@@ -41,17 +41,16 @@ public class UserService {
this.jwtService = jwtService;
}
- public User getUserById(Long userId) {
- return userRepository.findById(userId)
- .orElseThrow(() -> new NotAuthenticated("User not found"));
+ public Optional getUserById(Long userId) {
+ return userRepository.findById(userId);
}
- public User getLoggedInUser() {
+ public Optional getLoggedInUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
- if (auth != null && auth.isAuthenticated() && auth.getPrincipal() instanceof User) {
- return (User) auth.getPrincipal();
+ if (auth != null && auth.isAuthenticated() && auth.getPrincipal() instanceof User user) {
+ return Optional.of(user);
}
- return null;
+ return Optional.empty();
}
public String login(String idToken) {