diff --git a/.gitignore b/.gitignore index b8287c1..257eda7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,9 @@ backups/*.sql.gz backups/*.sql.zip backups/*.dump !backups/.gitkeep + +target/ +.idea/ +src/main/resources +**/application.properties +application.properties \ No newline at end of file diff --git a/init-db/03_schema.sql b/init-db/03_schema.sql index e5b33aa..e334b5a 100644 --- a/init-db/03_schema.sql +++ b/init-db/03_schema.sql @@ -190,7 +190,8 @@ CREATE TABLE employee ( id SERIAL PRIMARY KEY, role_id INT NOT NULL REFERENCES role(id), name VARCHAR(100) NOT NULL, - email VARCHAR(255) UNIQUE NOT NULL + email VARCHAR(255) UNIQUE NOT NULL, + account_id int references accounts(id) ); -- Insert initial lookup data @@ -289,3 +290,10 @@ INSERT INTO media_content_warning (media_id, content_warning_id) VALUES (4, 1), (4, 5), (4, 6), -- Pulp Fiction: Violence, Drug Abuse, Coarse Language (6, 1), (6, 2), -- Matrix: Violence, Fear (7, 1), (7, 5), (7, 6); -- Breaking Bad: Violence, Drug Abuse, Coarse Language + + +INSERT INTO employee (role_id, name, email) +VALUES + (1, 'Alice Junior', 'alice.junior@streamflix.com'), + (2, 'Bob Mid', 'bob.mid@streamflix.com'), + (3, 'Carol Senior', 'carol.senior@streamflix.com'); \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/config/SecurityConfig.java b/src/main/java/com/example/streamflix/config/SecurityConfig.java index 7cbac83..102eed4 100644 --- a/src/main/java/com/example/streamflix/config/SecurityConfig.java +++ b/src/main/java/com/example/streamflix/config/SecurityConfig.java @@ -1,5 +1,6 @@ package com.example.streamflix.config; +import io.netty.handler.codec.http.HttpMethod; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -30,6 +31,9 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/v1/auth/register", "/api/v1/auth/login", "/api/v1/auth/verify", "/api/v1/auth/forgot-password", "/api/v1/auth/reset-password").permitAll() + .requestMatchers("/api/v1/media/admin/**","/api/v1/media/movie/admin/**") + .hasAnyRole("Junior", "Mid-level", "Senior") + .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll() .requestMatchers("/api/v1/analytics/admin/**").authenticated() .requestMatchers("/api/v1/analytics/**").permitAll() diff --git a/src/main/java/com/example/streamflix/controller/MediaController.java b/src/main/java/com/example/streamflix/controller/MediaController.java index ae0746d..1d5d3d3 100644 --- a/src/main/java/com/example/streamflix/controller/MediaController.java +++ b/src/main/java/com/example/streamflix/controller/MediaController.java @@ -1,9 +1,12 @@ package com.example.streamflix.controller; -import com.example.streamflix.model.MediaDetailsDto; -import com.example.streamflix.model.StreamValidationResult; +import com.example.streamflix.entity.Media; +import com.example.streamflix.entity.Series; +import com.example.streamflix.model.*; import com.example.streamflix.enums.MediaQuality; import com.example.streamflix.service.MediaService; +import com.example.streamflix.service.MovieService; +import com.example.streamflix.service.SeriesService; import com.example.streamflix.service.StreamingService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -12,6 +15,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -25,10 +29,14 @@ public class MediaController { private final MediaService mediaService; private final StreamingService streamingService; + private final MovieService movieService; + private final SeriesService seriesService; - public MediaController(MediaService mediaService, StreamingService streamingService) { + public MediaController(MediaService mediaService, StreamingService streamingService, MovieService movieService, SeriesService seriesService) { this.mediaService = mediaService; this.streamingService = streamingService; + this.movieService = movieService; + this.seriesService = seriesService; } @Operation(summary = "Get available media", description = "Retrieve a list of media available for a specific profile") diff --git a/src/main/java/com/example/streamflix/controller/MovieController.java b/src/main/java/com/example/streamflix/controller/MovieController.java new file mode 100644 index 0000000..69eabaa --- /dev/null +++ b/src/main/java/com/example/streamflix/controller/MovieController.java @@ -0,0 +1,110 @@ +package com.example.streamflix.controller; + +import com.example.streamflix.entity.Movie; +import com.example.streamflix.model.MovieRequest; +import com.example.streamflix.service.MediaService; +import com.example.streamflix.service.MovieService; +import com.example.streamflix.service.SeriesService; +import com.example.streamflix.service.StreamingService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.persistence.Column; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +@RestController +@RequestMapping("/api/v1/media/movie") +@Tag(name = "Movie", description = "Operations related to media content and streaming") +public class MovieController { + + private final MediaService mediaService; + private final StreamingService streamingService; + private final MovieService movieService; + private final SeriesService seriesService; + + public MovieController(MediaService mediaService, + StreamingService streamingService, + MovieService movieService, + SeriesService seriesService) { + this.mediaService = mediaService; + this.streamingService = streamingService; + this.movieService = movieService; + this.seriesService = seriesService; + } + + + @Operation(summary = "Get all movies", + description = "Retrieves a complete list of all movies available in the database." + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successfully retrieved list"), + @ApiResponse(responseCode = "204", description = "No movies found in the database") + }) + @GetMapping("") + public List getAllMovies(){ + return movieService.getAllMovies(); + } + + @Operation( + summary = "Get movie by ID", + description = "Returns a single movie object based on its unique identifier." + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Movie found"), + @ApiResponse(responseCode = "404", description = "Movie not found with the provided ID") + }) + @GetMapping("{movieId}") + public ResponseEntity getMovieById(@PathVariable Long movieId){ + return movieService.getMovieById(movieId); + } + + @Operation( + summary = "Delete movie", + description = "Admin only: Removes a movie record from the system." + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Movie successfully deleted"), + @ApiResponse(responseCode = "404", description = "Movie not found") + }) + @DeleteMapping("/admin/{movieId}") + public Movie deleteMovieById(@PathVariable Long movieId){ + return movieService.deleteMovieById(movieId); + } + + @Operation( + summary = "Update movie details", + description = "Admin only: Updates an existing movie's information." + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Movie updated successfully"), + @ApiResponse(responseCode = "400", description = "Invalid input data"), + @ApiResponse(responseCode = "404", description = "Movie not found") + }) + @PutMapping("/admin/{movieId}") + public ResponseEntity updateMovieById(@PathVariable Long movieId, @RequestBody MovieRequest movieRequest){ + Object updated = movieService.updateMovie(movieId, movieRequest); + return ResponseEntity.ok(updated); + } + + @Operation( + summary = "Create a new movie", + description = "Admin only: Adds a new movie record to the catalog." + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Movie created successfully"), + @ApiResponse(responseCode = "400", description = "Invalid request body") + }) + @PostMapping("/admin") + public ResponseEntity createNewMovie(@RequestBody MovieRequest movieRequest){ + + Object created = movieService.createMovie(movieRequest); + return ResponseEntity.status(HttpStatus.CREATED).body(created); + } + +} diff --git a/src/main/java/com/example/streamflix/controller/SeriesController.java b/src/main/java/com/example/streamflix/controller/SeriesController.java new file mode 100644 index 0000000..01a605a --- /dev/null +++ b/src/main/java/com/example/streamflix/controller/SeriesController.java @@ -0,0 +1,95 @@ +package com.example.streamflix.controller; + +import com.example.streamflix.entity.Movie; +import com.example.streamflix.model.EpisodeRequest; +import com.example.streamflix.model.MovieRequest; +import com.example.streamflix.model.SeriesCreationRequest; +import com.example.streamflix.service.MediaService; +import com.example.streamflix.service.MovieService; +import com.example.streamflix.service.SeriesService; +import com.example.streamflix.service.StreamingService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.persistence.Column; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +@RestController +@RequestMapping("/api/v1/media/series") +@Tag(name = "Series", description = "Operations related to series") +public class SeriesController { + + private final MediaService mediaService; + private final StreamingService streamingService; + private final MovieService movieService; + private final SeriesService seriesService; + + public SeriesController(MediaService mediaService, + StreamingService streamingService, + MovieService movieService, + SeriesService seriesService) { + this.mediaService = mediaService; + this.streamingService = streamingService; + this.movieService = movieService; + this.seriesService = seriesService; + } + + @Operation(summary = "Get all series", description = "Returns a list of all series available in the system") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successfully retrieved list"), + @ApiResponse(responseCode = "204", description = "No series found") + }) + @GetMapping + public ResponseEntity> getAllSeries() { + List seriesList = seriesService.getSeriesList(); + if (seriesList.isEmpty()) { + return ResponseEntity.noContent().build(); + } + return ResponseEntity.ok(seriesList); + } + + @Operation(summary = "Get series by ID", description = "Retrieves a single series along with its seasons and episodes") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Found the series"), + @ApiResponse(responseCode = "404", description = "Series not found") + }) + @GetMapping("/{id}") + public ResponseEntity getSeriesById( + @Parameter(description = "ID of the series to be obtained", required = true) + @PathVariable Long id) { + + return seriesService.getSeriesById(id); + } + + @Operation(summary = "Create a new series", description = "Admin endpoint to initialize a new series") + @PostMapping("/admin/series") + public ResponseEntity createNewSeries(@RequestBody SeriesCreationRequest seriesCreationRequest){ + + Object created = seriesService.createFullSeries(seriesCreationRequest); + return ResponseEntity.status(HttpStatus.CREATED).body(created); + } + + @Operation(summary = "Create a new season", description = "Add a season to an existing series") + @PostMapping("/admin/series/season") + public ResponseEntity createNewSeason(@RequestBody SeriesCreationRequest seriesCreationRequest){ + + Object created = seriesService.createSeason(seriesCreationRequest); + return ResponseEntity.status(HttpStatus.CREATED).body(created); + } + + @Operation(summary = "Create a new episode", description = "Add an episode to an existing season") + @PostMapping("/admin/series/episode") + public ResponseEntity createNewEpisode(@RequestBody EpisodeRequest episodeRequest) { + Object created = seriesService.createEpisode(episodeRequest); + return ResponseEntity.status(HttpStatus.CREATED).body(created); + } + + +} diff --git a/src/main/java/com/example/streamflix/entity/Employee.java b/src/main/java/com/example/streamflix/entity/Employee.java index 095d9ec..78afa17 100644 --- a/src/main/java/com/example/streamflix/entity/Employee.java +++ b/src/main/java/com/example/streamflix/entity/Employee.java @@ -20,6 +20,10 @@ public class Employee { @Column(unique = true, nullable = false) private String email; + @ManyToOne + @JoinColumn(name = "account_id") + private Account account; + public Employee() { } @@ -60,4 +64,14 @@ public String getEmail() { public void setEmail(String email) { this.email = email; } + + public Account getAccount() + { + return this.account; + } + + public void setAccount(Account account) + { + this.account = account; + } } diff --git a/src/main/java/com/example/streamflix/entity/Episode.java b/src/main/java/com/example/streamflix/entity/Episode.java index 521d66a..4d8f0c6 100644 --- a/src/main/java/com/example/streamflix/entity/Episode.java +++ b/src/main/java/com/example/streamflix/entity/Episode.java @@ -1,6 +1,7 @@ package com.example.streamflix.entity; import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; import java.util.List; diff --git a/src/main/java/com/example/streamflix/entity/Media.java b/src/main/java/com/example/streamflix/entity/Media.java index 4fe3e44..d168515 100644 --- a/src/main/java/com/example/streamflix/entity/Media.java +++ b/src/main/java/com/example/streamflix/entity/Media.java @@ -1,5 +1,7 @@ package com.example.streamflix.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonManagedReference; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/com/example/streamflix/entity/Series.java b/src/main/java/com/example/streamflix/entity/Series.java index a2a05c6..8c8b363 100644 --- a/src/main/java/com/example/streamflix/entity/Series.java +++ b/src/main/java/com/example/streamflix/entity/Series.java @@ -27,9 +27,26 @@ public Series(AgeRating ageRating, String title, java.time.LocalDate releaseDate this.description = description; } - public String getDescription() { return description; } - public void setDescription(String description) { this.description = description; } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public List getSeasons() { + return seasons; + } + + public void setSeasons(List seasons) { + this.seasons = seasons; + } - public List getSeasons() { return seasons; } - public void setSeasons(List seasons) { this.seasons = seasons; } + public void addSeason(Season season) { + if (this.seasons == null) { + this.seasons = new ArrayList<>(); + } + this.seasons.add(season); + season.setSeries(this); + } } \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/model/EpisodeRequest.java b/src/main/java/com/example/streamflix/model/EpisodeRequest.java new file mode 100644 index 0000000..f6631ef --- /dev/null +++ b/src/main/java/com/example/streamflix/model/EpisodeRequest.java @@ -0,0 +1,71 @@ +package com.example.streamflix.model; + +public class EpisodeRequest +{ + private Long id; + private String title; + private int durationSeconds; + private String videoUrl; + private int episodeNumber; + private Long seasonId; + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public int getDurationSeconds() + { + return durationSeconds; + } + + public void setDurationSeconds(int durationSeconds) + { + this.durationSeconds = durationSeconds; + } + + public String getVideoUrl() + { + return videoUrl; + } + + public void setVideoUrl(String videoUrl) + { + this.videoUrl = videoUrl; + } + + public int getEpisodeNumber() + { + return episodeNumber; + } + + public void setEpisodeNumber(int episodeNumber) + { + this.episodeNumber = episodeNumber; + } + + public Long getSeasonId() + { + return this.seasonId; + } + + public void setSeasonId(Long seasonId) + { + this.seasonId = seasonId; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/model/MediaCreationRequest.java b/src/main/java/com/example/streamflix/model/MediaCreationRequest.java new file mode 100644 index 0000000..b1e3433 --- /dev/null +++ b/src/main/java/com/example/streamflix/model/MediaCreationRequest.java @@ -0,0 +1,208 @@ +package com.example.streamflix.model; + +import com.example.streamflix.entity.Episode; +import com.example.streamflix.entity.Season; +import com.example.streamflix.entity.Series; + +import java.time.LocalDate; + +public class MediaCreationRequest +{ + private Long id; + + //Fields for both media + private String ageRating; + private String title; + private LocalDate releaseDate; + private String externalId; + private String mediaType; + + //Series specific + private String seriesDescription; + + //Season specific + private Series series; + private int seasonNumber; + + //Episode specific + private Season season; + private Episode episode; + private int episodeNumber; + private int durationInSecond; + + // TMDB enriched data + private String posterUrl; + private String backdropUrl; + private String overview; + private Double externalRating; + + public Long getId() + { + return this.id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getAgeRating() + { + return this.ageRating; + } + + public void setAgeRating(String ageRating) + { + this.ageRating = ageRating; + } + + public String getTitle() + { + return this.title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public LocalDate getReleaseDate() + { + return this.releaseDate; + } + + public void setReleaseDate(LocalDate releaseDate) + { + this.releaseDate = releaseDate; + } + + public String getExternalId() + { + return this.externalId; + } + + public void setExternalId(String externalId) + { + this.externalId = externalId; + } + + public String getMediaType() + { + return this.mediaType; + } + + public void setMediaType(String mediaType) + { + this.mediaType = mediaType; + } + + public String getSeriesDescription() + { + return this.seriesDescription; + } + + public void setSeriesDescription(String seriesDescription) + { + this.seriesDescription = seriesDescription; + } + + public Series getSeries() + { + return this.series; + } + + public void setSeries(Series series) + { + this.series = series; + } + + public int getSeasonNumber() + { + return this.seasonNumber; + } + + public void setSeasonNumber(int seasonNumber) + { + this.seasonNumber = seasonNumber; + } + + public Season getSeason() + { + return this.season; + } + + public void setSeason(Season season) + { + this.season = season; + } + + public Episode getEpisode() + { + return this.episode; + } + + public void setEpisode(Episode episode) + { + this.episode = episode; + } + + public int getEpisodeNumber() + { + return this.episodeNumber; + } + + public void setEpisodeNumber(int episodeNumber) + { + this.episodeNumber = episodeNumber; + } + + public int getDurationInSecond() + { + return this.durationInSecond; + } + + public void setDurationInSecond(int durationInSecond) + { + this.durationInSecond = durationInSecond; + } + + public String getPosterUrl() + { + return this.posterUrl; + } + + public void setPosterUrl(String posterUrl) + { + this.posterUrl = posterUrl; + } + + public String getBackdropUrl() + { + return this.backdropUrl; + } + + public void setBackdropUrl(String backdropUrl) + { + this.backdropUrl = backdropUrl; + } + + public String getOverview() + { + return this.overview; + } + + public void setOverview(String overview) + { + this.overview = overview; + } + + public Double getExternalRating() + { + return this.externalRating; + } + + public void setExternalRating(Double externalRating) + { + this.externalRating = externalRating; + } +} diff --git a/src/main/java/com/example/streamflix/model/MediaDetailsDto.java b/src/main/java/com/example/streamflix/model/MediaDetailsDto.java index 21fbec3..4496e93 100644 --- a/src/main/java/com/example/streamflix/model/MediaDetailsDto.java +++ b/src/main/java/com/example/streamflix/model/MediaDetailsDto.java @@ -8,6 +8,9 @@ public class MediaDetailsDto { private LocalDate releaseDate; private String ageRating; private String externalId; + private String mediaType; + private Long seriesId; + private int durationInSecond; // TMDB enriched data private String posterUrl; @@ -87,4 +90,28 @@ public Double getExternalRating() { public void setExternalRating(Double externalRating) { this.externalRating = externalRating; } + + public String getMediaType() { + return this.mediaType; + } + + public void setMediaType(String mediaType) { + this.mediaType = mediaType; + } + + public Long getSeriesId() { + return this.seriesId; + } + + public void setSeriesId(Long seriesId) { + this.seriesId = seriesId; + } + + public int getDurationInSecond() { + return this.durationInSecond; + } + + public void setDurationInSecond(int durationInSecond) { + this.durationInSecond = durationInSecond; + } } \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/model/MovieMapper.java b/src/main/java/com/example/streamflix/model/MovieMapper.java new file mode 100644 index 0000000..af0b08a --- /dev/null +++ b/src/main/java/com/example/streamflix/model/MovieMapper.java @@ -0,0 +1,5 @@ +package com.example.streamflix.model; + +public class MovieMapper +{ +} diff --git a/src/main/java/com/example/streamflix/model/MovieRequest.java b/src/main/java/com/example/streamflix/model/MovieRequest.java new file mode 100644 index 0000000..f619fa0 --- /dev/null +++ b/src/main/java/com/example/streamflix/model/MovieRequest.java @@ -0,0 +1,131 @@ +package com.example.streamflix.model; + +import java.time.LocalDate; + +public class MovieRequest +{ + + private Long id; + private String ageRating; + private String title; + private LocalDate releaseDate; + private String externalId; + private String mediaType; + private int durationInSecond; + + // TMDB enriched data + private String posterUrl; + private String backdropUrl; + private String overview; + private Double externalRating; + + public Long getId() + { + return this.id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getAgeRating() + { + return this.ageRating; + } + + public void setAgeRating(String ageRating) + { + this.ageRating = ageRating; + } + + public String getTitle() + { + return this.title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public LocalDate getReleaseDate() + { + return this.releaseDate; + } + + public void setReleaseDate(LocalDate releaseDate) + { + this.releaseDate = releaseDate; + } + + public String getExternalId() + { + return this.externalId; + } + + public void setExternalId(String externalId) + { + this.externalId = externalId; + } + + public String getMediaType() + { + return this.mediaType; + } + + public void setMediaType(String mediaType) + { + this.mediaType = mediaType; + } + + public int getDurationInSecond() + { + return this.durationInSecond; + } + + public void setDurationInSecond(int durationInSecond) + { + this.durationInSecond = durationInSecond; + } + + public String getPosterUrl() + { + return this.posterUrl; + } + + public void setPosterUrl(String posterUrl) + { + this.posterUrl = posterUrl; + } + + public String getBackdropUrl() + { + return this.backdropUrl; + } + + public void setBackdropUrl(String backdropUrl) + { + this.backdropUrl = backdropUrl; + } + + public String getOverview() + { + return this.overview; + } + + public void setOverview(String overview) + { + this.overview = overview; + } + + public Double getExternalRating() + { + return this.externalRating; + } + + public void setExternalRating(Double externalRating) + { + this.externalRating = externalRating; + } +} diff --git a/src/main/java/com/example/streamflix/model/SeriesCreationRequest.java b/src/main/java/com/example/streamflix/model/SeriesCreationRequest.java new file mode 100644 index 0000000..f75cbdb --- /dev/null +++ b/src/main/java/com/example/streamflix/model/SeriesCreationRequest.java @@ -0,0 +1,179 @@ +package com.example.streamflix.model; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class SeriesCreationRequest +{ + private Long id; + private String title; + private LocalDate releaseDate; + private String ageRating; + private String externalId; + private String mediaType; + private String description; + + private Long seriesId; + private Long seasonId; + private int seasonNumber; + + private List episodeList = new ArrayList<>(); + + // TMDB enriched data + private String posterUrl; + private String backdropUrl; + private String overview; + private Double externalRating; + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public LocalDate getReleaseDate() + { + return releaseDate; + } + + public void setReleaseDate(LocalDate releaseDate) + { + this.releaseDate = releaseDate; + } + + public String getAgeRating() + { + return ageRating; + } + + public void setAgeRating(String ageRating) + { + this.ageRating = ageRating; + } + + public String getExternalId() + { + return externalId; + } + + public void setExternalId(String externalId) + { + this.externalId = externalId; + } + + public String getMediaType() + { + return mediaType; + } + + public void setMediaType(String mediaType) + { + this.mediaType = mediaType; + } + + public String getDescription() + { + return this.description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public Long getSeriesId() + { + return seriesId; + } + + public void setSeriesId(Long seriesId) + { + this.seriesId = seriesId; + } + + public Long getSeasonId() + { + return seasonId; + } + + public void setSeasonId(Long seasonId) + { + this.seasonId = seasonId; + } + + public int getSeasonNumber() + { + return seasonNumber; + } + + public void setSeasonNumber(int seasonNumber) + { + this.seasonNumber = seasonNumber; + } + + public List getEpisodeList() + { + return episodeList; + } + + + public void addEpisode(EpisodeRequest episode) + { + this.episodeList.add(episode); + } + + public String getPosterUrl() + { + return posterUrl; + } + + public void setPosterUrl(String posterUrl) + { + this.posterUrl = posterUrl; + } + + public String getBackdropUrl() + { + return backdropUrl; + } + + public void setBackdropUrl(String backdropUrl) + { + this.backdropUrl = backdropUrl; + } + + public String getOverview() + { + return overview; + } + + public void setOverview(String overview) + { + this.overview = overview; + } + + public Double getExternalRating() + { + return externalRating; + } + + public void setExternalRating(Double externalRating) + { + this.externalRating = externalRating; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/repository/AccountRepository.java b/src/main/java/com/example/streamflix/repository/AccountRepository.java index 562787a..559f730 100644 --- a/src/main/java/com/example/streamflix/repository/AccountRepository.java +++ b/src/main/java/com/example/streamflix/repository/AccountRepository.java @@ -2,8 +2,11 @@ import com.example.streamflix.entity.Account; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + import java.util.Optional; +@Repository public interface AccountRepository extends JpaRepository { Optional findByEmail(String email); } diff --git a/src/main/java/com/example/streamflix/repository/AgeRatingRepository.java b/src/main/java/com/example/streamflix/repository/AgeRatingRepository.java index 63229a3..37ceced 100644 --- a/src/main/java/com/example/streamflix/repository/AgeRatingRepository.java +++ b/src/main/java/com/example/streamflix/repository/AgeRatingRepository.java @@ -2,6 +2,12 @@ import com.example.streamflix.entity.AgeRating; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.Optional; + +@Repository public interface AgeRatingRepository extends JpaRepository { + boolean existsByLabel(String label); + Optional findByLabel(String label); } \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/repository/EmployeeRepository.java b/src/main/java/com/example/streamflix/repository/EmployeeRepository.java index e87053b..b9c6dd6 100644 --- a/src/main/java/com/example/streamflix/repository/EmployeeRepository.java +++ b/src/main/java/com/example/streamflix/repository/EmployeeRepository.java @@ -1,5 +1,6 @@ package com.example.streamflix.repository; +import com.example.streamflix.entity.Account; import com.example.streamflix.entity.Employee; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -9,4 +10,5 @@ @Repository public interface EmployeeRepository extends JpaRepository { Optional findByEmail(String email); + Optional findByAccount(Account account); } diff --git a/src/main/java/com/example/streamflix/repository/EpisodeRepository.java b/src/main/java/com/example/streamflix/repository/EpisodeRepository.java index 85293e8..8af6169 100644 --- a/src/main/java/com/example/streamflix/repository/EpisodeRepository.java +++ b/src/main/java/com/example/streamflix/repository/EpisodeRepository.java @@ -2,8 +2,16 @@ import com.example.streamflix.entity.Episode; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + import java.util.List; +import java.util.Optional; +@Repository public interface EpisodeRepository extends JpaRepository { List findBySeasonIdOrderByEpisodeNumber(Long seasonId); + Optional findByTitle(String title); + boolean existsByTitle(String title); + boolean existsBySeasonAndTitle(String title, Long seasonID,int episodeNumber); + boolean existsBySeasonIdAndEpisodeNumber(Long seasonId, int seasonNumber); } diff --git a/src/main/java/com/example/streamflix/repository/MediaRepository.java b/src/main/java/com/example/streamflix/repository/MediaRepository.java index b3747bd..8deb3ed 100644 --- a/src/main/java/com/example/streamflix/repository/MediaRepository.java +++ b/src/main/java/com/example/streamflix/repository/MediaRepository.java @@ -2,9 +2,12 @@ import com.example.streamflix.entity.Media; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; import java.util.Optional; +@Repository public interface MediaRepository extends JpaRepository { Optional findById(Long id); + boolean existsByTitle(String title); } diff --git a/src/main/java/com/example/streamflix/repository/MovieRepository.java b/src/main/java/com/example/streamflix/repository/MovieRepository.java index 58ce6f2..dc11c70 100644 --- a/src/main/java/com/example/streamflix/repository/MovieRepository.java +++ b/src/main/java/com/example/streamflix/repository/MovieRepository.java @@ -2,7 +2,10 @@ import com.example.streamflix.entity.Movie; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + import java.util.Optional; +@Repository public interface MovieRepository extends JpaRepository { } diff --git a/src/main/java/com/example/streamflix/repository/ProfileRepository.java b/src/main/java/com/example/streamflix/repository/ProfileRepository.java index 581d4ff..ccb9a1a 100644 --- a/src/main/java/com/example/streamflix/repository/ProfileRepository.java +++ b/src/main/java/com/example/streamflix/repository/ProfileRepository.java @@ -2,8 +2,11 @@ import com.example.streamflix.entity.Profile; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + import java.util.List; +@Repository public interface ProfileRepository extends JpaRepository { List findByAccountId(Long accountId); } \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/repository/SeasonRepository.java b/src/main/java/com/example/streamflix/repository/SeasonRepository.java index 3ef9e32..28c54db 100644 --- a/src/main/java/com/example/streamflix/repository/SeasonRepository.java +++ b/src/main/java/com/example/streamflix/repository/SeasonRepository.java @@ -1,9 +1,14 @@ package com.example.streamflix.repository; import com.example.streamflix.entity.Season; +import com.example.streamflix.entity.Series; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + import java.util.List; +@Repository public interface SeasonRepository extends JpaRepository { List findBySeriesIdOrderBySeasonNumber(Long seriesId); + boolean existsBySeriesIdAndSeasonNumber(Long seriesId, int number); } diff --git a/src/main/java/com/example/streamflix/repository/SeriesRepository.java b/src/main/java/com/example/streamflix/repository/SeriesRepository.java index 117844e..e15ec1b 100644 --- a/src/main/java/com/example/streamflix/repository/SeriesRepository.java +++ b/src/main/java/com/example/streamflix/repository/SeriesRepository.java @@ -2,7 +2,10 @@ import com.example.streamflix.entity.Series; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + import java.util.Optional; +@Repository public interface SeriesRepository extends JpaRepository { } diff --git a/src/main/java/com/example/streamflix/security/CustomUserDetails.java b/src/main/java/com/example/streamflix/security/CustomUserDetails.java index c16f019..73d5d26 100644 --- a/src/main/java/com/example/streamflix/security/CustomUserDetails.java +++ b/src/main/java/com/example/streamflix/security/CustomUserDetails.java @@ -2,17 +2,20 @@ import com.example.streamflix.entity.Account; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; -import java.util.Collections; +import java.util.List; public class CustomUserDetails implements UserDetails { private final Account account; + private final String roleName; - public CustomUserDetails(Account account) { + public CustomUserDetails(Account account, String roleName) { this.account = account; + this.roleName = roleName; } public Account getAccount() { @@ -21,7 +24,11 @@ public Account getAccount() { @Override public Collection getAuthorities() { - return Collections.emptyList(); + if (roleName == null) { + return List.of(); + } + + return List.of(new SimpleGrantedAuthority("ROLE_" + roleName)); } @Override diff --git a/src/main/java/com/example/streamflix/service/AccountUserDetailsService.java b/src/main/java/com/example/streamflix/service/AccountUserDetailsService.java index e1aff8c..a45f7a7 100644 --- a/src/main/java/com/example/streamflix/service/AccountUserDetailsService.java +++ b/src/main/java/com/example/streamflix/service/AccountUserDetailsService.java @@ -1,27 +1,59 @@ package com.example.streamflix.service; import com.example.streamflix.entity.Account; +import com.example.streamflix.entity.Employee; import com.example.streamflix.repository.AccountRepository; +import com.example.streamflix.repository.EmployeeRepository; // Add this import com.example.streamflix.security.CustomUserDetails; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; +import java.util.Optional; + @Service public class AccountUserDetailsService implements UserDetailsService { private final AccountRepository accountRepository; + private final EmployeeRepository employeeRepository; - public AccountUserDetailsService(AccountRepository accountRepository) { + public AccountUserDetailsService(AccountRepository accountRepository, + EmployeeRepository employeeRepository) { this.accountRepository = accountRepository; + this.employeeRepository = employeeRepository; } @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + Account account = accountRepository.findByEmail(email) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + email)); - return new CustomUserDetails(account); + Optional employeeOpt = employeeRepository.findByAccount(account); + String roleName; + + if (employeeOpt.isPresent()) { + + Employee foundEmployee = employeeOpt.get(); + Long roleId; + + if (foundEmployee.getRole() == null) { + roleId = 0L; + } else { + roleId = foundEmployee.getRole().getId(); + } + + roleName = switch (roleId.intValue()) { + case 1 -> "Junior"; + case 2 -> "Mid-level"; + case 3 -> "Senior"; + default -> "User"; + }; + } else { + roleName = "User"; + } + + return new CustomUserDetails(account, roleName); } -} +} \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/service/AgeRatingService.java b/src/main/java/com/example/streamflix/service/AgeRatingService.java new file mode 100644 index 0000000..b471762 --- /dev/null +++ b/src/main/java/com/example/streamflix/service/AgeRatingService.java @@ -0,0 +1,28 @@ +package com.example.streamflix.service; + +import com.example.streamflix.entity.AgeRating; +import com.example.streamflix.repository.AgeRatingRepository; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class AgeRatingService { + + private final AgeRatingRepository ageRatingRepository; + + public AgeRatingService(AgeRatingRepository ageRatingRepository) { + this.ageRatingRepository = ageRatingRepository; + } + + public Long findIdByLabel(String label) { + return ageRatingRepository.findByLabel(label) + .map(AgeRating::getId) + .orElseThrow(() -> + new IllegalArgumentException( + "AgeRating not found with name: " + label + ) + ); + } + +} \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/service/MediaService.java b/src/main/java/com/example/streamflix/service/MediaService.java index 3f903e4..b48980f 100644 --- a/src/main/java/com/example/streamflix/service/MediaService.java +++ b/src/main/java/com/example/streamflix/service/MediaService.java @@ -1,35 +1,54 @@ package com.example.streamflix.service; +import com.example.streamflix.entity.*; +import com.example.streamflix.model.MediaCreationRequest; import com.example.streamflix.model.MediaDetailsDto; -import com.example.streamflix.entity.Media; -import com.example.streamflix.entity.Profile; import com.example.streamflix.exception.NotFoundException; -import com.example.streamflix.repository.MediaRepository; -import com.example.streamflix.repository.ProfileRepository; +import com.example.streamflix.model.SeriesCreationRequest; +import com.example.streamflix.repository.*; import com.example.streamflix.util.SecurityUtils; +import jakarta.transaction.Transactional; import org.springframework.stereotype.Service; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; @Service -public class MediaService { +public class MediaService +{ private final MediaRepository mediaRepository; private final ProfileRepository profileRepository; + private final AgeRatingRepository ageRatingRepository; + private final EpisodeRepository episodeRepository; + private final SeriesRepository seriesRepository; + private final SeasonRepository seasonRepository; private final TmdbService tmdbService; private final ContentAccessService contentAccessService; + private final AgeRatingService ageRatingService; private final SecurityUtils securityUtils; public MediaService(MediaRepository mediaRepository, ProfileRepository profileRepository, + AgeRatingRepository ageRatingRepository, + EpisodeRepository episodeRepository, + SeriesRepository seriesRepository, + SeasonRepository seasonRepository, TmdbService tmdbService, ContentAccessService contentAccessService, - SecurityUtils securityUtils) { + AgeRatingService ageRatingService, + SecurityUtils securityUtils) + { this.mediaRepository = mediaRepository; this.profileRepository = profileRepository; + this.ageRatingRepository = ageRatingRepository; + this.episodeRepository = episodeRepository; + this.seriesRepository = seriesRepository; + this.seasonRepository = seasonRepository; this.tmdbService = tmdbService; this.contentAccessService = contentAccessService; + this.ageRatingService = ageRatingService; this.securityUtils = securityUtils; } @@ -135,4 +154,22 @@ private void enrichWithTmdbData(MediaDetailsDto dto, String externalId) { System.err.println("Failed to fetch TMDB data: " + e.getMessage()); } } + + @Transactional + public Media deleteMedia(Long mediaId) { + + Media media = mediaRepository.findById(mediaId) + .orElseThrow(() -> new NotFoundException("Media not found")); + + mediaRepository.delete(media); + + return media; + } + + private AgeRating getAgeRating(String label) { + return ageRatingRepository.findByLabel(label) + .orElseThrow(() -> new NotFoundException("Age Rating not found: " + label)); + } + + } \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/service/MovieService.java b/src/main/java/com/example/streamflix/service/MovieService.java new file mode 100644 index 0000000..17d79d2 --- /dev/null +++ b/src/main/java/com/example/streamflix/service/MovieService.java @@ -0,0 +1,136 @@ +package com.example.streamflix.service; + +import com.example.streamflix.entity.AgeRating; +import com.example.streamflix.entity.Movie; +import com.example.streamflix.entity.Series; +import com.example.streamflix.exception.NotFoundException; +import com.example.streamflix.model.MediaCreationRequest; +import com.example.streamflix.model.MovieRequest; +import com.example.streamflix.model.SeriesCreationRequest; +import com.example.streamflix.repository.*; +import com.example.streamflix.util.SecurityUtils; +import jakarta.transaction.Transactional; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class MovieService +{ + private final MediaRepository mediaRepository; + private final ProfileRepository profileRepository; + private final AgeRatingRepository ageRatingRepository; + private final EpisodeRepository episodeRepository; + private final SeriesRepository seriesRepository; + private final SeasonRepository seasonRepository; + private final TmdbService tmdbService; + private final ContentAccessService contentAccessService; + private final AgeRatingService ageRatingService; + private final SecurityUtils securityUtils; + private final MovieRepository movieRepository; + + public MovieService(MediaRepository mediaRepository, + ProfileRepository profileRepository, + AgeRatingRepository ageRatingRepository, + EpisodeRepository episodeRepository, + SeriesRepository seriesRepository, + SeasonRepository seasonRepository, + TmdbService tmdbService, + ContentAccessService contentAccessService, + AgeRatingService ageRatingService, + SecurityUtils securityUtils, MovieRepository movieRepository) + { + this.mediaRepository = mediaRepository; + this.profileRepository = profileRepository; + this.ageRatingRepository = ageRatingRepository; + this.episodeRepository = episodeRepository; + this.seriesRepository = seriesRepository; + this.seasonRepository = seasonRepository; + this.tmdbService = tmdbService; + this.contentAccessService = contentAccessService; + this.ageRatingService = ageRatingService; + this.securityUtils = securityUtils; + this.movieRepository = movieRepository; + } + + public Movie createMovie(MovieRequest movieRequest) { + + if (mediaRepository.existsByTitle(movieRequest.getTitle())) { + throw new IllegalStateException("Movie already exists"); + } + + AgeRating ageRating = (ageRatingRepository.findByLabel(movieRequest.getAgeRating())) + .orElseThrow(() -> new RuntimeException("ageRating is not found")); + + + Movie movie = new Movie(); + movie.setTitle(movieRequest.getTitle()); + movie.setAgeRating(ageRating); + movie.setReleaseDate(movieRequest.getReleaseDate()); + movie.setDurationSeconds(movieRequest.getDurationInSecond()); + movie.setVideoUrl(movieRequest.getBackdropUrl()); + + return mediaRepository.save(movie); + } + + + @Transactional + public Movie deleteMovieById(Long id) { + + Movie movieToDelete = movieRepository.findById(id) + .orElseThrow(()->new RuntimeException("Movie is not found")); + + movieRepository.delete(movieToDelete); + + return movieToDelete; + } + + @Transactional + public Movie updateMovie(Long movieId, MovieRequest movieRequest) + { + Movie movieToEdit = movieRepository.findById(movieId) + .orElseThrow(()-> new RuntimeException("No movie to edit has been found")); + + if(movieRequest.getTitle() != null) + { + movieToEdit.setTitle(movieRequest.getTitle()); + } + + if(movieRequest.getAgeRating() != null) + { + movieToEdit.setAgeRating(getAgeRating(movieRequest.getAgeRating())); + } + + if(movieRequest.getBackdropUrl() != null) + { + movieToEdit.setVideoUrl(movieRequest.getBackdropUrl()); + } + + if(movieRequest.getDurationInSecond() > 0) + { + movieToEdit.setDurationSeconds(movieRequest.getDurationInSecond()); + } + + return movieToEdit; + } + + private AgeRating getAgeRating(String label) { + return ageRatingRepository.findByLabel(label) + .orElseThrow(() -> new NotFoundException("Age Rating not found: " + label)); + } + + public ResponseEntity getMovieById(Long id) + { + return movieRepository.findById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + public List getAllMovies() + { + return movieRepository.findAll(); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/example/streamflix/service/SeriesService.java b/src/main/java/com/example/streamflix/service/SeriesService.java new file mode 100644 index 0000000..33d89e7 --- /dev/null +++ b/src/main/java/com/example/streamflix/service/SeriesService.java @@ -0,0 +1,165 @@ +package com.example.streamflix.service; + +import com.example.streamflix.entity.AgeRating; +import com.example.streamflix.entity.Episode; +import com.example.streamflix.entity.Season; +import com.example.streamflix.entity.Series; +import com.example.streamflix.model.EpisodeRequest; +import com.example.streamflix.model.SeriesCreationRequest; +import com.example.streamflix.repository.*; +import com.example.streamflix.util.SecurityUtils; +import jakarta.persistence.EntityNotFoundException; +import jakarta.transaction.Transactional; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class SeriesService +{ + private final MediaRepository mediaRepository; + private final ProfileRepository profileRepository; + private final AgeRatingRepository ageRatingRepository; + private final EpisodeRepository episodeRepository; + private final SeriesRepository seriesRepository; + private final SeasonRepository seasonRepository; + private final TmdbService tmdbService; + private final ContentAccessService contentAccessService; + private final AgeRatingService ageRatingService; + private final SecurityUtils securityUtils; + + public SeriesService(MediaRepository mediaRepository, + ProfileRepository profileRepository, + AgeRatingRepository ageRatingRepository, + EpisodeRepository episodeRepository, + SeriesRepository seriesRepository, + SeasonRepository seasonRepository, + TmdbService tmdbService, + ContentAccessService contentAccessService, + AgeRatingService ageRatingService, + SecurityUtils securityUtils) + { + this.mediaRepository = mediaRepository; + this.profileRepository = profileRepository; + this.ageRatingRepository = ageRatingRepository; + this.episodeRepository = episodeRepository; + this.seriesRepository = seriesRepository; + this.seasonRepository = seasonRepository; + this.tmdbService = tmdbService; + this.contentAccessService = contentAccessService; + this.ageRatingService = ageRatingService; + this.securityUtils = securityUtils; + } + + @Transactional + public Series createFullSeries(SeriesCreationRequest request) { + + Series series = createSeries(request); + Season season = createNewSeasonForSeries(series, request.getSeasonNumber()); + + if (request.getEpisodeList() != null) { + for (EpisodeRequest epDto : request.getEpisodeList()) { + createNewEpisode(epDto, season); + } + } + + return seriesRepository.save(series); + } + + public Series createSeries(SeriesCreationRequest request) { + + if(request == null) { + throw new IllegalArgumentException("Series creation request cannot be null"); + } + + if (mediaRepository.existsByTitle(request.getTitle())) { + throw new IllegalStateException("Series already exists"); + } + + AgeRating ageRating = (ageRatingRepository.findByLabel(request.getAgeRating())) + .orElseThrow(() -> new RuntimeException("ageRating is not found")); + + Series series = new Series(); + series.setTitle(request.getTitle()); + series.setDescription(request.getDescription()); + series.setAgeRating(ageRating); + series.setReleaseDate(request.getReleaseDate()); + + series.setSeasons(new ArrayList<>()); + + return seriesRepository.save(series); + } + + private Season createNewSeasonForSeries(Series series, int seasonNumber) { + + if (series.getId() == null) { + throw new RuntimeException("Series (with id) must be provided"); + } + + if(seasonNumber == 0) { + seasonNumber = 1; + } + + Series managedSeries = seriesRepository.findById(series.getId()) + .orElseThrow(() -> new RuntimeException("Series does not exist")); + + if(seasonRepository.existsBySeriesIdAndSeasonNumber(managedSeries.getId(),seasonNumber)){ + throw new RuntimeException("Season already exists"); + } + + Season seasonToAdd = new Season(); + seasonToAdd.setSeasonNumber(seasonNumber); + seasonToAdd.setSeries(managedSeries); + + return seasonRepository.save(seasonToAdd); + } + + public Season createSeason(SeriesCreationRequest request) { + + Series series = seriesRepository.findById(request.getSeriesId()) + .orElseThrow(() -> new EntityNotFoundException("Series not found")); + + return createNewSeasonForSeries(series, request.getSeasonNumber()); + } + + private Episode createNewEpisode(EpisodeRequest request, Season managedSeason) { + + if(request.getTitle() == null || managedSeason.getId() == null || request.getVideoUrl() == null) { + throw new RuntimeException("Some important data is null"); + } + + if(episodeRepository.findByTitle(request.getTitle()).isPresent() + && episodeRepository.existsBySeasonIdAndEpisodeNumber(request.getSeasonId(), request.getEpisodeNumber())) { + throw new RuntimeException("Title already exist or episodeNumberAlreadyOccupied"); + } + + Episode episodeToadd = new Episode(); + episodeToadd.setTitle(request.getTitle()); + episodeToadd.setSeason(managedSeason); + episodeToadd.setEpisodeNumber(request.getEpisodeNumber()); + episodeToadd.setVideoUrl(request.getVideoUrl()); + episodeToadd.setDurationSeconds(request.getDurationSeconds()); + + return episodeRepository.save(episodeToadd); + } + + public Episode createEpisode(EpisodeRequest episodeRequest) { + Season season = seasonRepository.findById(episodeRequest.getSeasonId()) + .orElseThrow(() -> new EntityNotFoundException("season not found")); + + return createNewEpisode(episodeRequest, season); + } + + public List getSeriesList(){ + + return seriesRepository.findAll(); + } + + public ResponseEntity getSeriesById(Long seriesId) { + return seriesRepository.findById(seriesId) + .map(ResponseEntity::ok) + .orElseThrow(()-> new EntityNotFoundException("series not found")); + } + +} diff --git a/src/main/java/com/example/streamflix/util/SecurityUtils.java b/src/main/java/com/example/streamflix/util/SecurityUtils.java index c668910..d4a36ac 100644 --- a/src/main/java/com/example/streamflix/util/SecurityUtils.java +++ b/src/main/java/com/example/streamflix/util/SecurityUtils.java @@ -3,11 +3,14 @@ import com.example.streamflix.service.JwtService; import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import static org.springframework.security.authorization.AuthorityReactiveAuthorizationManager.*; + @Component public class SecurityUtils {