-
Notifications
You must be signed in to change notification settings - Fork 19
Mats branch 2 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f1f2086
8520f86
55e019d
ed40602
d1aaae6
3b2957d
03b2221
1787dbe
8ff13d2
d01637d
8252c5b
ab21961
2730c42
c86c7ed
676443f
2ea5a94
69db4ee
eeaaf32
e3f0aeb
2235457
a9161ab
7faddff
5df2668
c98bf88
a34a97b
5b899fd
30c1788
113e894
67a689a
02513de
5e5c93f
9f53a78
8d4a332
67ca487
a9cc81b
ee1ae4f
20acec2
bffbf99
e710b6b
720d615
32e412c
d61ead3
25951ac
4fee174
3d13bc7
4d18099
64b14d3
d2fdea1
5364429
5f8f90c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| target/ | ||
| /.idea/ | ||
| .env |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| version: "3.8" | ||
|
|
||
| services: | ||
| mysql: | ||
| image: mysql:8.3 | ||
| container_name: movieapp_mysql | ||
| restart: always | ||
| environment: | ||
| MYSQL_ROOT_PASSWORD: rootpass | ||
| MYSQL_DATABASE: moviedb | ||
| MYSQL_USER: movieuser | ||
| MYSQL_PASSWORD: moviepass | ||
|
Comment on lines
+9
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move database credentials to environment variables. Hardcoding database credentials directly in 🔎 Recommended approach using environment variablesCreate a MYSQL_ROOT_PASSWORD=rootpass
MYSQL_DATABASE=moviedb
MYSQL_USER=movieuser
MYSQL_PASSWORD=moviepassThen reference them in docker-compose.yml: environment:
- MYSQL_ROOT_PASSWORD: rootpass
- MYSQL_DATABASE: moviedb
- MYSQL_USER: movieuser
- MYSQL_PASSWORD: moviepass
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
+ MYSQL_DATABASE: ${MYSQL_DATABASE}
+ MYSQL_USER: ${MYSQL_USER}
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD}Provide a 🤖 Prompt for AI Agents |
||
| ports: | ||
| - "127.0.0.1:3306:3306" | ||
| volumes: | ||
| - mysql_data:/var/lib/mysql | ||
|
|
||
| volumes: | ||
| mysql_data: | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,16 @@ | |
| <mockito.version>5.21.0</mockito.version> | ||
| </properties> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>com.google.code.gson</groupId> | ||
| <artifactId>gson</artifactId> | ||
| <version>2.10.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.github.cdimascio</groupId> | ||
| <artifactId>dotenv-java</artifactId> | ||
| <version>3.0.0</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter</artifactId> | ||
|
|
@@ -50,5 +60,42 @@ | |
| <artifactId>classgraph</artifactId> | ||
| <version>4.8.184</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>jakarta.persistence</groupId> | ||
| <artifactId>jakarta.persistence-api</artifactId> | ||
| <version>3.2.0</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.slf4j</groupId> | ||
| <artifactId>slf4j-api</artifactId> | ||
| <version>2.0.13</version> | ||
| </dependency> | ||
|
Comment on lines
+68
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SLF4J API without a binding will produce warnings. Adding 🤖 Prompt for AI Agents |
||
| <dependency> | ||
| <groupId>org.openjfx</groupId> | ||
| <artifactId>javafx-media</artifactId> | ||
| <version>25.0.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.openjfx</groupId> | ||
| <artifactId>javafx-controls</artifactId> | ||
| <version>25.0.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.openjfx</groupId> | ||
| <artifactId>javafx-fxml</artifactId> | ||
| <version>25.0.1</version> | ||
| </dependency> | ||
| </dependencies> | ||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.openjfx</groupId> | ||
| <artifactId>javafx-maven-plugin</artifactId> | ||
| <version>0.0.8</version> | ||
| <configuration> | ||
| <mainClass>org.example.App</mainClass> | ||
| </configuration> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,23 @@ | ||
| package org.example; | ||
|
|
||
| public class App { | ||
| import javafx.application.Application; | ||
| import javafx.stage.Stage; | ||
| import org.example.ui.MainApp; | ||
| import org.example.util.JPAUtil; | ||
|
|
||
| public class App extends Application { | ||
|
|
||
| @Override | ||
| public void start(Stage primaryStage) { | ||
| MainApp mainApp = new MainApp(); | ||
| mainApp.start(primaryStage); | ||
| } | ||
|
|
||
| public static void main(String[] args) { | ||
| System.out.println("Hello There!"); | ||
| launch(args); | ||
|
|
||
| JPAUtil.inTransaction(em -> { | ||
| System.out.println("Database schema initialized"); | ||
| }); | ||
| } | ||
|
Comment on lines
16
to
22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Database initialization runs after application exits.
🔎 Proposed fix public static void main(String[] args) {
+ // Initialize database before starting UI
+ JPAUtil.inTransaction(em -> {
+ System.out.println("Database schema initialized");
+ });
+
launch(args);
-
- JPAUtil.inTransaction(em -> {
- System.out.println("Database schema initialized");
- });
}🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| package org.example.api; | ||
|
|
||
| import com.google.gson.Gson; | ||
| import io.github.cdimascio.dotenv.Dotenv; | ||
| import nonapi.io.github.classgraph.json.JSONUtils; | ||
| import org.example.dto.CreditsDTO; | ||
| import org.example.dto.MovieDetailsDTO; | ||
| import org.example.dto.TopRatedResponseDTO; | ||
|
|
||
| import java.net.URI; | ||
| import java.net.http.HttpClient; | ||
| import java.net.http.HttpRequest; | ||
| import java.net.http.HttpResponse; | ||
| import java.time.Duration; | ||
|
|
||
| public class TmdbClient { | ||
|
|
||
| private final String apiKey; | ||
| private final String baseUrl; | ||
| private final HttpClient httpClient; | ||
| private final Gson gson; | ||
|
|
||
|
|
||
| public TmdbClient() { | ||
| this(HttpClient.newHttpClient(), new Gson()); | ||
| } | ||
|
|
||
|
|
||
| public TmdbClient(HttpClient httpClient, Gson gson) { | ||
|
|
||
| Dotenv dotenv = Dotenv.load(); | ||
|
|
||
| this.apiKey = dotenv.get("TMDB_API_KEY"); | ||
| this.baseUrl = dotenv.get("TMDB_BASE_URL"); | ||
|
|
||
| if (apiKey == null || baseUrl == null) { | ||
| throw new IllegalArgumentException("TMDB config missing in .env"); | ||
| } | ||
|
|
||
| this.httpClient = httpClient; | ||
| this.gson = gson; | ||
| } | ||
|
|
||
| public TmdbClient(HttpClient httpClient, Gson gson, String apiKey, String baseUrl) { | ||
| if (apiKey == null || baseUrl == null) { | ||
| throw new IllegalArgumentException("TMDB config missing"); | ||
| } | ||
|
|
||
| this.httpClient = httpClient; | ||
| this.gson = gson; | ||
| this.apiKey = apiKey; | ||
| this.baseUrl = baseUrl; | ||
| System.out.println("TMDB BASE URL = " + baseUrl); | ||
| } | ||
|
|
||
| public TopRatedResponseDTO getTopRatedMovies() { | ||
| try { | ||
| String url = baseUrl + "/movie/top_rated?api_key=" + apiKey; | ||
|
|
||
| HttpRequest request = HttpRequest.newBuilder() | ||
| .uri(URI.create(url)) | ||
| .timeout(Duration.ofSeconds(10)) | ||
| .GET() | ||
| .build(); | ||
|
|
||
| HttpResponse<String> response = | ||
| httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||
|
|
||
| if (response.statusCode() != 200) { | ||
| throw new RuntimeException( | ||
| "TMDB API error: HTTP " + response.statusCode() + " - " + response.body() | ||
| ); | ||
| } | ||
|
|
||
| return gson.fromJson(response.body(), TopRatedResponseDTO.class); | ||
|
|
||
| } catch (Exception e) { | ||
| throw new RuntimeException("Could not get top rated movies from TMDB", e); | ||
| } | ||
| } | ||
|
Comment on lines
+56
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Use TMDB Access Token with Authorization header instead of api_key query parameter. The API key is currently passed as a query parameter. If logged anywhere—in error messages, debugging output, or monitoring systems—the API key could be exposed. TMDB API supports a more secure approach: obtain an API Read Access Token from account settings and send it as an Authorization header. This eliminates the risk of accidental exposure through URL logging while providing a read-only authentication method. 🤖 Prompt for AI Agents |
||
|
|
||
| public MovieDetailsDTO getMovieDetails(int movieId) { | ||
| try { | ||
| String url = baseUrl + "/movie/" + movieId + "?api_key=" + apiKey; | ||
|
|
||
| HttpRequest request = HttpRequest.newBuilder() | ||
| .uri(URI.create(url)) | ||
| .timeout(Duration.ofSeconds(10)) | ||
| .GET() | ||
| .build(); | ||
|
|
||
| HttpResponse<String> response = | ||
| httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||
|
|
||
| if (response.statusCode() != 200) { | ||
| throw new RuntimeException( | ||
| "TMDB API error: HTTP " + response.statusCode() + " - " + response.body() | ||
| ); | ||
| } | ||
|
|
||
| return gson.fromJson(response.body(), MovieDetailsDTO.class); | ||
|
|
||
| } catch (Exception e) { | ||
| throw new RuntimeException("Could not get movie details from TMDB", e); | ||
| } | ||
| } | ||
|
|
||
| public CreditsDTO getMovieCredits(int movieId) { | ||
| try { | ||
| String url = baseUrl + "/movie/" + movieId + "/credits?api_key=" + apiKey; | ||
|
|
||
| HttpRequest request = HttpRequest.newBuilder() | ||
| .uri(URI.create(url)) | ||
| .timeout(Duration.ofSeconds(10)) | ||
| .GET() | ||
| .build(); | ||
|
|
||
| HttpResponse<String> response = | ||
| httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||
|
|
||
| if (response.statusCode() != 200) { | ||
| throw new RuntimeException( | ||
| "TMDB API error: HTTP " + response.statusCode() + " - " + response.body() | ||
| ); | ||
| } | ||
|
|
||
| return gson.fromJson(response.body(), CreditsDTO.class); | ||
|
|
||
| } catch (Exception e) { | ||
| throw new RuntimeException("Could not get movie credits from TMDB", e); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,10 @@ | ||||||
| package org.example.dto; | ||||||
|
|
||||||
| import com.google.gson.annotations.SerializedName; | ||||||
|
|
||||||
| public record CastDTO ( | ||||||
| int id, | ||||||
| String name, | ||||||
| @SerializedName("profile_path") String profilePath, | ||||||
| int order // 0 = main actor, 2 = second actor, 3 = third actor etc. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment appears to have a typo. The comment states "0 = main actor, 2 = second actor" but likely should be "0 = main actor, 1 = second actor, 2 = third actor" based on typical zero-based ordering. 🔎 Proposed fix- int order // 0 = main actor, 2 = second actor, 3 = third actor etc.
+ int order // 0 = main actor, 1 = second actor, 2 = third actor, etc.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| ) {} | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package org.example.dto; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record CreditsDTO( | ||
| int id, | ||
| List<CastDTO> cast, | ||
| List<CrewDTO> crew | ||
| ) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package org.example.dto; | ||
|
|
||
| import com.google.gson.annotations.SerializedName; | ||
|
|
||
| public record CrewDTO( | ||
| int id, | ||
| String name, | ||
| @SerializedName("profile_path") String profilePath, | ||
| String job | ||
| ) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package org.example.dto; | ||
|
|
||
| import com.google.gson.annotations.SerializedName; | ||
|
|
||
| public record MovieDTO( | ||
| int id, | ||
| String title, | ||
| String overview, | ||
| @SerializedName("release_date") String releaseDate, | ||
| @SerializedName("vote_average") double voteAverage, | ||
| @SerializedName("poster_path") String posterPath | ||
| ) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package org.example.dto; | ||
|
|
||
| import com.google.gson.annotations.SerializedName; | ||
|
|
||
| public record MovieDetailsDTO( | ||
| int id, | ||
| String title, | ||
| String overview, | ||
| @SerializedName("release_date") String releaseDate, | ||
| int runtime, | ||
| @SerializedName("vote_average") double voteAverage, | ||
| @SerializedName("poster_path") String posterPath | ||
|
|
||
| // Should we add a genre DTO? | ||
| ) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package org.example.dto; | ||
|
|
||
| import com.google.gson.annotations.SerializedName; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record TopRatedResponseDTO( | ||
| int page, | ||
| List<MovieDTO> results, | ||
| @SerializedName("total_pages") int totalPages, | ||
| @SerializedName("total_results") int totalResults | ||
| ) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix markdown checkbox syntax.
The completed checkboxes use
[ x ]which won't render properly in markdown. Remove the space between[andxfor correct rendering.🔎 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents