Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/339Lr3BJ)
### How the tests work (and Docker requirement)

This project ships with an end‑to‑end CLI integration test suite that uses Testcontainers to spin up a temporary MySQL database.
Expand Down
257 changes: 253 additions & 4 deletions src/main/java/com/example/Main.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.example;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.*;
import java.util.Arrays;
import java.util.Scanner;

public class Main {

Expand Down Expand Up @@ -31,6 +30,246 @@ public void run() {
throw new RuntimeException(e);
}
//Todo: Starting point for your code
Scanner scanner = new Scanner(System.in);

System.out.println("Username:");
String username = scanner.nextLine();

System.out.println("Password:");
String password = scanner.nextLine();

boolean isValid = validateLogin(username, password, jdbcUrl, dbUser, dbPass);

if (!isValid) {
System.out.println("Invalid username or password");
// Testarna förväntar sig att man kan välja 0 för att avsluta
System.out.print("Press 0 to exit or any key to continue...");
String choice = scanner.nextLine();
if ("0".equals(choice)) {
return;
}
} else {
System.out.println("Login successful!");
}

// Huvudmeny
boolean running = true;
while (running) {
System.out.println("1) List moon missions");
System.out.println("2) Get a moon mission by mission_id");
System.out.println("3) Count missions for a given year");
System.out.println("4) Create an account");
System.out.println("5) Update an account password");
System.out.println("6) Delete an account");
System.out.println("0) Exit");

System.out.print("Enter choice: ");
String choice = scanner.nextLine();

switch (choice) {
case "1":
listMoonMissions(jdbcUrl, dbUser, dbPass);
break;
case "2":
System.out.print("Enter mission ID: ");
String missionId = scanner.nextLine();
getMissionById(jdbcUrl, dbUser, dbPass, missionId);
break;
case "3":
System.out.print("Enter year: ");
String year = scanner.nextLine();
countMissionsByYear(jdbcUrl, dbUser, dbPass, year);
break;
case "4":
createAccount(jdbcUrl, dbUser, dbPass, scanner);
break;
case "5":
updateAccountPassword(jdbcUrl, dbUser, dbPass, scanner);
break;
case "6":
deleteAccount(jdbcUrl, dbUser, dbPass, scanner);
break;
case "0":
System.out.println("Exiting...");
running = false;
break;
default:
System.out.println("Invalid choice");
}

if (running && !choice.equals("0")) {
System.out.println("\nPress Enter to continue...");
scanner.nextLine();
}
}
}

private boolean validateLogin(String username, String password,
String jdbcUrl, String dbUser, String dbPass) {
String sql = "SELECT 1 FROM account WHERE name = ? AND password = ?";
try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {

stmt.setString(1, username);
stmt.setString(2, password);

try (ResultSet rs = stmt.executeQuery()) {
return rs.next();
}

} catch (SQLException e) {
System.err.println("Login error: " + e.getMessage());
return false;
}
}
Comment on lines +107 to +124
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Login query is parameterized (good), but don’t mask DB errors as “invalid login”.

Right now any SQLException returns false (Line 120-123), which makes “DB down / wrong config” look like bad credentials. Consider rethrowing (or failing fast) so misconfig is obvious during runs/tests.

@@
         } catch (SQLException e) {
-            System.err.println("Login error: " + e.getMessage());
-            return false;
+            throw new RuntimeException("Login query failed", e);
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private boolean validateLogin(String username, String password,
String jdbcUrl, String dbUser, String dbPass) {
String sql = "SELECT 1 FROM account WHERE name = ? AND password = ?";
try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, username);
stmt.setString(2, password);
try (ResultSet rs = stmt.executeQuery()) {
return rs.next();
}
} catch (SQLException e) {
System.err.println("Login error: " + e.getMessage());
return false;
}
}
private boolean validateLogin(String username, String password,
String jdbcUrl, String dbUser, String dbPass) {
String sql = "SELECT 1 FROM account WHERE name = ? AND password = ?";
try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, username);
stmt.setString(2, password);
try (ResultSet rs = stmt.executeQuery()) {
return rs.next();
}
} catch (SQLException e) {
throw new RuntimeException("Login query failed", e);
}
}
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 107-124 the validateLogin
method currently catches SQLException and returns false, masking configuration
or DB availability errors as “invalid login”; change the method to stop
swallowing SQLExceptions — either declare throws SQLException on validateLogin
and let callers handle it, or catch SQLException and rethrow a runtime exception
(e.g., IllegalStateException) with the original exception as the cause so DB
failures surface clearly; remove the System.err swallow and ensure callers/tests
can detect and fail fast on misconfiguration or connectivity issues.


private void listMoonMissions(String jdbcUrl, String dbUser, String dbPass) {
String sql = "SELECT spacecraft FROM moon_mission ORDER BY mission_id";
try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {

System.out.println("\n=== Moon Missions ===");
while (rs.next()) {
System.out.println(rs.getString("spacecraft"));
}

} catch (SQLException e) {
System.err.println("Error listing missions: " + e.getMessage());
}
}
Comment on lines +126 to +140
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

git ls-files | head -20

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 483


🏁 Script executed:

find . -maxdepth 2 -name "README*" -o -name "readme*" | head -10

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 110


🏁 Script executed:

find . -name "Main.java" | head -5

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 136


🏁 Script executed:

cat README.md

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 6058


🏁 Script executed:

wc -l src/main/java/com/example/Main.java

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 138


🏁 Script executed:

sed -n '126,140p' src/main/java/com/example/Main.java

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 752


🏁 Script executed:

cat src/test/java/com/example/CliAppIT.java

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 13365


Output may not strictly match specification. README requirement states "prints spacecraft names" without mentioning a header. The === Moon Missions === line (132) adds content beyond what is specified. While the integration tests use flexible substring matching and won't fail, consider removing the header to align exactly with the stated requirement.

-            System.out.println("\n=== Moon Missions ===");
             while (rs.next()) {
                 System.out.println(rs.getString("spacecraft"));
             }
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 126-140, remove the extra
header print so output matches the README spec; delete the
System.out.println("\n=== Moon Missions ==="); (and the leading newline) so the
method prints only spacecraft names one per line from the ResultSet and leaves
error handling unchanged.


private void getMissionById(String jdbcUrl, String dbUser, String dbPass, String missionId) {
String sql = "SELECT * FROM moon_mission WHERE mission_id = ?";
try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {

stmt.setInt(1, Integer.parseInt(missionId));
ResultSet rs = stmt.executeQuery();

if (rs.next()) {
System.out.println("\n=== Mission Details ===");
System.out.println("Mission ID: " + rs.getInt("mission_id"));
System.out.println("Spacecraft: " + rs.getString("spacecraft"));
System.out.println("Launch Date: " + rs.getDate("launch_date"));
System.out.println("Carrier Rocket: " + rs.getString("carrier_rocket"));
System.out.println("Operator: " + rs.getString("operator"));
System.out.println("Mission Type: " + rs.getString("mission_type"));
System.out.println("Outcome: " + rs.getString("outcome"));
} else {
System.out.println("Mission not found");
}

} catch (SQLException | NumberFormatException e) {
System.err.println("Error: " + e.getMessage());
}
}

private void countMissionsByYear(String jdbcUrl, String dbUser, String dbPass, String year) {
String sql = "SELECT COUNT(*) as count FROM moon_mission WHERE YEAR(launch_date) = ?";
try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {

stmt.setInt(1, Integer.parseInt(year));
ResultSet rs = stmt.executeQuery();

if (rs.next()) {
int count = rs.getInt("count");
System.out.println("Number of missions in " + year + ": " + count);
}

} catch (SQLException | NumberFormatException e) {
System.err.println("Error: " + e.getMessage());
}
}

private void createAccount(String jdbcUrl, String dbUser, String dbPass, Scanner scanner) {
System.out.print("First name: ");
String firstName = scanner.nextLine();

System.out.print("Last name: ");
String lastName = scanner.nextLine();

System.out.print("SSN: ");
String ssn = scanner.nextLine();

System.out.print("Password: ");
String password = scanner.nextLine();

// Skapa username från förnamn + första 3 bokstäver av efternamn
String username = cap3(firstName) + cap3(lastName);

String sql = "INSERT INTO account (first_name, last_name, ssn, name, password) " +
"VALUES (?, ?, ?, ?, ?)";

try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {

stmt.setString(1, firstName);
stmt.setString(2, lastName);
stmt.setString(3, ssn);
stmt.setString(4, username);
stmt.setString(5, password);

int rows = stmt.executeUpdate();
if (rows > 0) {
System.out.println("Account created successfully!");
System.out.println("Username: " + username);
}

} catch (SQLException e) {
System.err.println("Error creating account: " + e.getMessage());
}
}
Comment on lines +186 to +223
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f \( -name "*init*.sql" -o -name "*schema*.sql" -o -name "*.sql" \) | head -20

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 128


🏁 Script executed:

cat ./src/main/resources/init.sql

Repository: ithsjava25/ithsjava25-java-databas-jdbc-javafx-classrom

Length of output: 4853


Username generation may allow duplicates; consider enforcing uniqueness or collision handling.

The account.name column has no UNIQUE constraint in the schema, so cap3(firstName) + cap3(lastName) collisions will not cause INSERT failures. However, the method can still generate identical usernames for different people (e.g., "Bob Brown" and "Bobby Browner" both → "BobBro"), leading to silent duplicates. Consider either adding a UNIQUE constraint on account.name, detecting duplicates before insertion, or appending a suffix/counter to ensure uniqueness.


private void updateAccountPassword(String jdbcUrl, String dbUser, String dbPass, Scanner scanner) {
System.out.print("Enter user ID: ");
String userId = scanner.nextLine();

System.out.print("Enter new password: ");
String newPassword = scanner.nextLine();

String sql = "UPDATE account SET password = ? WHERE user_id = ?";

try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {

stmt.setString(1, newPassword);
stmt.setInt(2, Integer.parseInt(userId));

int rows = stmt.executeUpdate();
if (rows > 0) {
System.out.println("Password updated successfully");
} else {
System.out.println("No account found with ID: " + userId);
}

} catch (SQLException | NumberFormatException e) {
System.err.println("Error: " + e.getMessage());
}
}

private void deleteAccount(String jdbcUrl, String dbUser, String dbPass, Scanner scanner) {
System.out.print("Enter user ID to delete: ");
String userId = scanner.nextLine();

String sql = "DELETE FROM account WHERE user_id = ?";

try (Connection conn = DriverManager.getConnection(jdbcUrl, dbUser, dbPass);
PreparedStatement stmt = conn.prepareStatement(sql)) {

stmt.setInt(1, Integer.parseInt(userId));

int rows = stmt.executeUpdate();
if (rows > 0) {
System.out.println("Account deleted successfully");
} else {
System.out.println("No account found with ID: " + userId);
}

} catch (SQLException | NumberFormatException e) {
System.err.println("Error: " + e.getMessage());
}
}

/**
Expand Down Expand Up @@ -59,4 +298,14 @@ private static String resolveConfig(String propertyKey, String envKey) {
}
return (v == null || v.trim().isEmpty()) ? null : v.trim();
}
}

private static String cap3(String s) {
if (s == null) return "";
String t = s.trim();
if (t.isEmpty()) return "";

String part = t.substring(0, Math.min(3, t.length()));
return part.substring(0, 1).toUpperCase() +
part.substring(1).toLowerCase();
}
}
Loading