From db2731ed057d6a15debebe7bb081bc8924d25d90 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:28:30 +0000 Subject: [PATCH 1/3] add deadline --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d20aaf9..7071577 100644 --- a/README.md +++ b/README.md @@ -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. From 85e4ec80c0b5a32f1d499c2c05f015fcfe677ac3 Mon Sep 17 00:00:00 2001 From: Oscar Nidemar Date: Fri, 12 Dec 2025 13:38:45 +0100 Subject: [PATCH 2/3] restart test --- pom.xml | 5 + src/main/java/com/example/Account.java | 10 ++ .../java/com/example/AccountRepository.java | 9 ++ .../com/example/AccountRepositoryJdbc.java | 90 ++++++++++++ .../com/example/DevDatabaseInitializer.java | 2 + src/main/java/com/example/Main.java | 137 +++++++++++++++--- src/main/java/com/example/MoonMission.java | 14 ++ .../com/example/MoonMissionRepository.java | 11 ++ .../example/MoonMissionRepositoryJdbc.java | 76 ++++++++++ .../SimpleDriverManagerDataSource.java | 21 +++ 10 files changed, 351 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/example/Account.java create mode 100644 src/main/java/com/example/AccountRepository.java create mode 100644 src/main/java/com/example/AccountRepositoryJdbc.java create mode 100644 src/main/java/com/example/MoonMission.java create mode 100644 src/main/java/com/example/MoonMissionRepository.java create mode 100644 src/main/java/com/example/MoonMissionRepositoryJdbc.java create mode 100644 src/main/java/com/example/SimpleDriverManagerDataSource.java diff --git a/pom.xml b/pom.xml index 002ff66..017178d 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,11 @@ ${junit.jupiter.version} test + + org.slf4j + slf4j-nop + 2.0.17 + org.assertj assertj-core diff --git a/src/main/java/com/example/Account.java b/src/main/java/com/example/Account.java new file mode 100644 index 0000000..9d7fe06 --- /dev/null +++ b/src/main/java/com/example/Account.java @@ -0,0 +1,10 @@ +package com.example; + +public record Account( + int userId, + String name, + String password, + String firstName, + String lastName, + String ssn +) {} \ No newline at end of file diff --git a/src/main/java/com/example/AccountRepository.java b/src/main/java/com/example/AccountRepository.java new file mode 100644 index 0000000..80b0231 --- /dev/null +++ b/src/main/java/com/example/AccountRepository.java @@ -0,0 +1,9 @@ +package com.example; +import java.util.Optional; + +public interface AccountRepository { + Optional findByNameAndPassword(String name, String password); + Account create(Account account); + boolean updatePassword(int userId, String newPassword); + boolean delete(int userId); +} diff --git a/src/main/java/com/example/AccountRepositoryJdbc.java b/src/main/java/com/example/AccountRepositoryJdbc.java new file mode 100644 index 0000000..ddb94dd --- /dev/null +++ b/src/main/java/com/example/AccountRepositoryJdbc.java @@ -0,0 +1,90 @@ +package com.example; + + +import com.example.SimpleDriverManagerDataSource; + +import java.sql.*; +import java.util.Optional; + +public class AccountRepositoryJdbc implements AccountRepository { + private final SimpleDriverManagerDataSource ds; + + public AccountRepositoryJdbc(SimpleDriverManagerDataSource ds) { + this.ds = ds; + } + + @Override + public Optional findByNameAndPassword(String name, String password) { + String sql = "SELECT * FROM account WHERE name = ? AND password = ?"; + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, name); + ps.setString(2, password); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return Optional.of(new Account( + rs.getInt("user_id"), + rs.getString("name"), + rs.getString("password"), + rs.getString("first_name"), + rs.getString("last_name"), + rs.getString("ssn") + )); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return Optional.empty(); + } + + @Override + public Account create(Account account) { + String sql = "INSERT INTO account (name, password, first_name, last_name, ssn) VALUES (?, ?, ?, ?, ?)"; + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + ps.setString(1, account.name()); + ps.setString(2, account.password()); + ps.setString(3, account.firstName()); + ps.setString(4, account.lastName()); + ps.setString(5, account.ssn()); + ps.executeUpdate(); + try (ResultSet keys = ps.getGeneratedKeys()) { + if (keys.next()) { + return new Account(keys.getInt(1), account.name(), account.password(), + account.firstName(), account.lastName(), account.ssn()); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return account; + } + + @Override + public boolean updatePassword(int userId, String newPassword) { + String sql = "UPDATE account SET password = ? WHERE user_id = ?"; + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, newPassword); + ps.setInt(2, userId); + return ps.executeUpdate() > 0; + } catch (SQLException e) { + e.printStackTrace(); + } + return false; + } + + @Override + public boolean delete(int userId) { + String sql = "DELETE FROM account WHERE user_id = ?"; + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setInt(1, userId); + return ps.executeUpdate() > 0; + } catch (SQLException e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/src/main/java/com/example/DevDatabaseInitializer.java b/src/main/java/com/example/DevDatabaseInitializer.java index e8a45fe..b6323f0 100644 --- a/src/main/java/com/example/DevDatabaseInitializer.java +++ b/src/main/java/com/example/DevDatabaseInitializer.java @@ -16,9 +16,11 @@ public static void start() { .withInitScript("init.sql"); mysql.start(); + System.setProperty("APP_JDBC_URL", mysql.getJdbcUrl()); System.setProperty("APP_DB_USER", mysql.getUsername()); System.setProperty("APP_DB_PASS", mysql.getPassword()); + System.out.println("Init script loaded, JDBC URL: " + mysql.getJdbcUrl()); } } } diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 6dc6fbd..b6c6e52 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -1,10 +1,18 @@ package com.example; +import com.example.Account; +import com.example.AccountRepository; +import com.example.AccountRepositoryJdbc; +import com.example.MoonMissionRepository; +import com.example.MoonMissionRepositoryJdbc; + import java.sql.Connection; -import java.sql.DriverManager; +import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.util.Arrays; + public class Main { static void main(String[] args) { @@ -15,43 +23,124 @@ static void main(String[] args) { } public void run() { - // Resolve DB settings with precedence: System properties -> Environment variables String jdbcUrl = resolveConfig("APP_JDBC_URL", "APP_JDBC_URL"); String dbUser = resolveConfig("APP_DB_USER", "APP_DB_USER"); String dbPass = resolveConfig("APP_DB_PASS", "APP_DB_PASS"); + System.out.println("Connecting to DB: " + jdbcUrl); + System.out.println("DB User: " + dbUser); if (jdbcUrl == null || dbUser == null || dbPass == null) { - throw new IllegalStateException( - "Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " + - "as system properties (-Dkey=value) or environment variables."); + throw new IllegalStateException("Missing DB configuration..."); } - try (Connection connection = DriverManager.getConnection(jdbcUrl, dbUser, dbPass)) { + SimpleDriverManagerDataSource ds = new SimpleDriverManagerDataSource(jdbcUrl, dbUser, dbPass); + AccountRepository accountRepo = new AccountRepositoryJdbc(ds); + MoonMissionRepository missionRepo = new MoonMissionRepositoryJdbc(ds); + //Seed data test + try (Connection conn = ds.getConnection(); + Statement st = conn.createStatement(); + ResultSet rs = st.executeQuery("SELECT name, password FROM account")) { + while (rs.next()) { + System.out.println("Seed account: " + rs.getString("name") + " / " + rs.getString("password")); + } } catch (SQLException e) { - throw new RuntimeException(e); + e.printStackTrace(); + } + + + System.out.println("Username:"); + String username = IO.readln(); + System.out.println("Password:"); + String password = IO.readln(); + + if (accountRepo.findByNameAndPassword(username, password).isPresent()) { + System.out.println("username accepted"); + menuLoop(accountRepo, missionRepo); + } else { + System.out.println("Invalid username or password"); + System.out.println("0) Exit"); + String opt = IO.readln(); + if ("0".equals(opt)) { + return; + } + } + } + + private void menuLoop(AccountRepository accountRepo, MoonMissionRepository missionRepo) { + boolean running = true; + while (running) { + System.out.println("Menu:"); + System.out.println("1) List moon missions"); + System.out.println("2) Get mission by id"); + System.out.println("3) Count missions by year"); + System.out.println("4) Create account"); + System.out.println("5) Update account password"); + System.out.println("6) Delete account"); + System.out.println("0) Exit"); + + String choice = IO.readln(); + switch (choice) { + case "1": + missionRepo.findAll().forEach(m -> System.out.println(m.spacecraft())); + break; + case "2": + System.out.println("mission_id:"); + int id = Integer.parseInt(IO.readln()); + missionRepo.findById(id).ifPresentOrElse( + m -> System.out.println("Mission " + m.missionId() + ": " + m.spacecraft()), + () -> System.out.println("No mission found") + ); + break; + case "3": + System.out.println("year:"); + int year = Integer.parseInt(IO.readln()); + int count = missionRepo.countByYear(year); + System.out.println(count); + break; + case "4": + System.out.println("first name:"); + String fn = IO.readln(); + System.out.println("last name:"); + String ln = IO.readln(); + System.out.println("ssn:"); + String ssn = IO.readln(); + System.out.println("password:"); + String pw = IO.readln(); + String name = fn.substring(0,3) + ln.substring(0,3); + accountRepo.create(new Account(0, name, pw, fn, ln, ssn)); + System.out.println("account created"); + break; + case "5": + System.out.println("user_id:"); + int uid = Integer.parseInt(IO.readln()); + System.out.println("new password:"); + String newPw = IO.readln(); + if (accountRepo.updatePassword(uid, newPw)) { + System.out.println("updated"); + } + break; + case "6": + System.out.println("user_id:"); + int delId = Integer.parseInt(IO.readln()); + if (accountRepo.delete(delId)) { + System.out.println("deleted"); + } + break; + case "0": + running = false; + break; + default: + System.out.println("Invalid option"); + } } - //Todo: Starting point for your code } - /** - * Determines if the application is running in development mode based on system properties, - * environment variables, or command-line arguments. - * - * @param args an array of command-line arguments - * @return {@code true} if the application is in development mode; {@code false} otherwise - */ private static boolean isDevMode(String[] args) { - if (Boolean.getBoolean("devMode")) //Add VM option -DdevMode=true - return true; - if ("true".equalsIgnoreCase(System.getenv("DEV_MODE"))) //Environment variable DEV_MODE=true - return true; - return Arrays.asList(args).contains("--dev"); //Argument --dev + if (Boolean.getBoolean("devMode")) return true; + if ("true".equalsIgnoreCase(System.getenv("DEV_MODE"))) return true; + return Arrays.asList(args).contains("--dev"); } - /** - * Reads configuration with precedence: Java system property first, then environment variable. - * Returns trimmed value or null if neither source provides a non-empty value. - */ private static String resolveConfig(String propertyKey, String envKey) { String v = System.getProperty(propertyKey); if (v == null || v.trim().isEmpty()) { diff --git a/src/main/java/com/example/MoonMission.java b/src/main/java/com/example/MoonMission.java new file mode 100644 index 0000000..777204f --- /dev/null +++ b/src/main/java/com/example/MoonMission.java @@ -0,0 +1,14 @@ +package com.example; + +import java.time.LocalDate; + +public record MoonMission( + int missionId, + String spacecraft, + LocalDate launchDate, + String carrierRocket, + String operator, + String missionType, + String outcome +) {} + diff --git a/src/main/java/com/example/MoonMissionRepository.java b/src/main/java/com/example/MoonMissionRepository.java new file mode 100644 index 0000000..f961d1a --- /dev/null +++ b/src/main/java/com/example/MoonMissionRepository.java @@ -0,0 +1,11 @@ +package com.example; + +import com.example.MoonMission; +import java.util.List; +import java.util.Optional; + +public interface MoonMissionRepository { + List findAll(); + Optional findById(int missionId); + int countByYear(int year); +} diff --git a/src/main/java/com/example/MoonMissionRepositoryJdbc.java b/src/main/java/com/example/MoonMissionRepositoryJdbc.java new file mode 100644 index 0000000..2a31b7f --- /dev/null +++ b/src/main/java/com/example/MoonMissionRepositoryJdbc.java @@ -0,0 +1,76 @@ +package com.example; + +import java.sql.*; +import java.util.*; + +public class MoonMissionRepositoryJdbc implements MoonMissionRepository { + private final SimpleDriverManagerDataSource ds; + + public MoonMissionRepositoryJdbc(SimpleDriverManagerDataSource ds) { + this.ds = ds; + } + + @Override + public List findAll() { + List missions = new ArrayList<>(); + String sql = "SELECT * FROM moon_mission ORDER BY mission_id"; + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql); + ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + missions.add(new MoonMission( + rs.getInt("mission_id"), + rs.getString("spacecraft"), + rs.getDate("launch_date").toLocalDate(), + rs.getString("carrier_rocket"), + rs.getString("operator"), + rs.getString("mission_type"), + rs.getString("outcome") + )); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return missions; + } + + @Override + public Optional findById(int missionId) { + String sql = "SELECT * FROM moon_mission WHERE mission_id = ?"; + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setInt(1, missionId); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return Optional.of(new MoonMission( + rs.getInt("mission_id"), + rs.getString("spacecraft"), + rs.getDate("launch_date").toLocalDate(), + rs.getString("carrier_rocket"), + rs.getString("operator"), + rs.getString("mission_type"), + rs.getString("outcome") + )); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return Optional.empty(); + } + + @Override + public int countByYear(int year) { + String sql = "SELECT COUNT(*) FROM moon_mission WHERE YEAR(launch_date) = ?"; + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setInt(1, year); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) return rs.getInt(1); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return 0; + } +} diff --git a/src/main/java/com/example/SimpleDriverManagerDataSource.java b/src/main/java/com/example/SimpleDriverManagerDataSource.java new file mode 100644 index 0000000..cdda3bf --- /dev/null +++ b/src/main/java/com/example/SimpleDriverManagerDataSource.java @@ -0,0 +1,21 @@ +package com.example; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class SimpleDriverManagerDataSource { + private final String url; + private final String user; + private final String pass; + + public SimpleDriverManagerDataSource(String url, String user, String pass) { + this.url = url; + this.user = user; + this.pass = pass; + } + + public Connection getConnection() throws SQLException { + return DriverManager.getConnection(url, user, pass); + } +} From 96f413bca61b684661be1eb40412f5f0ef9a5b89 Mon Sep 17 00:00:00 2001 From: Oscar Nidemar Date: Fri, 12 Dec 2025 14:52:38 +0100 Subject: [PATCH 3/3] =?UTF-8?q?testerna=20gr=C3=B6na?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/Main.java | 56 +++++++++++------------------ src/main/resources/init.sql | 1 - 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index b6c6e52..5bc2b8b 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -1,21 +1,16 @@ package com.example; + import com.example.Account; import com.example.AccountRepository; import com.example.AccountRepositoryJdbc; import com.example.MoonMissionRepository; import com.example.MoonMissionRepositoryJdbc; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; import java.util.Arrays; - +import java.util.Scanner; public class Main { - - static void main(String[] args) { + public static void main(String[] args) { if (isDevMode(args)) { DevDatabaseInitializer.start(); } @@ -26,8 +21,6 @@ public void run() { String jdbcUrl = resolveConfig("APP_JDBC_URL", "APP_JDBC_URL"); String dbUser = resolveConfig("APP_DB_USER", "APP_DB_USER"); String dbPass = resolveConfig("APP_DB_PASS", "APP_DB_PASS"); - System.out.println("Connecting to DB: " + jdbcUrl); - System.out.println("DB User: " + dbUser); if (jdbcUrl == null || dbUser == null || dbPass == null) { throw new IllegalStateException("Missing DB configuration..."); @@ -36,37 +29,28 @@ public void run() { SimpleDriverManagerDataSource ds = new SimpleDriverManagerDataSource(jdbcUrl, dbUser, dbPass); AccountRepository accountRepo = new AccountRepositoryJdbc(ds); MoonMissionRepository missionRepo = new MoonMissionRepositoryJdbc(ds); - //Seed data test - try (Connection conn = ds.getConnection(); - Statement st = conn.createStatement(); - ResultSet rs = st.executeQuery("SELECT name, password FROM account")) { - while (rs.next()) { - System.out.println("Seed account: " + rs.getString("name") + " / " + rs.getString("password")); - } - } catch (SQLException e) { - e.printStackTrace(); - } + Scanner sc = new Scanner(System.in); System.out.println("Username:"); - String username = IO.readln(); + String username = sc.nextLine(); System.out.println("Password:"); - String password = IO.readln(); + String password = sc.nextLine(); if (accountRepo.findByNameAndPassword(username, password).isPresent()) { System.out.println("username accepted"); - menuLoop(accountRepo, missionRepo); + menuLoop(accountRepo, missionRepo, sc); } else { System.out.println("Invalid username or password"); System.out.println("0) Exit"); - String opt = IO.readln(); + String opt = sc.nextLine(); if ("0".equals(opt)) { return; } } } - private void menuLoop(AccountRepository accountRepo, MoonMissionRepository missionRepo) { + private void menuLoop(AccountRepository accountRepo, MoonMissionRepository missionRepo, Scanner sc) { boolean running = true; while (running) { System.out.println("Menu:"); @@ -78,14 +62,14 @@ private void menuLoop(AccountRepository accountRepo, MoonMissionRepository missi System.out.println("6) Delete account"); System.out.println("0) Exit"); - String choice = IO.readln(); + String choice = sc.nextLine(); switch (choice) { case "1": missionRepo.findAll().forEach(m -> System.out.println(m.spacecraft())); break; case "2": System.out.println("mission_id:"); - int id = Integer.parseInt(IO.readln()); + int id = Integer.parseInt(sc.nextLine()); missionRepo.findById(id).ifPresentOrElse( m -> System.out.println("Mission " + m.missionId() + ": " + m.spacecraft()), () -> System.out.println("No mission found") @@ -93,35 +77,35 @@ private void menuLoop(AccountRepository accountRepo, MoonMissionRepository missi break; case "3": System.out.println("year:"); - int year = Integer.parseInt(IO.readln()); + int year = Integer.parseInt(sc.nextLine()); int count = missionRepo.countByYear(year); - System.out.println(count); + System.out.println(count + " missions in " + year); break; case "4": System.out.println("first name:"); - String fn = IO.readln(); + String fn = sc.nextLine(); System.out.println("last name:"); - String ln = IO.readln(); + String ln = sc.nextLine(); System.out.println("ssn:"); - String ssn = IO.readln(); + String ssn = sc.nextLine(); System.out.println("password:"); - String pw = IO.readln(); + String pw = sc.nextLine(); String name = fn.substring(0,3) + ln.substring(0,3); accountRepo.create(new Account(0, name, pw, fn, ln, ssn)); System.out.println("account created"); break; case "5": System.out.println("user_id:"); - int uid = Integer.parseInt(IO.readln()); + int uid = Integer.parseInt(sc.nextLine()); System.out.println("new password:"); - String newPw = IO.readln(); + String newPw = sc.nextLine(); if (accountRepo.updatePassword(uid, newPw)) { System.out.println("updated"); } break; case "6": System.out.println("user_id:"); - int delId = Integer.parseInt(IO.readln()); + int delId = Integer.parseInt(sc.nextLine()); if (accountRepo.delete(delId)) { System.out.println("deleted"); } diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql index e4ffd06..fa390ed 100644 --- a/src/main/resources/init.sql +++ b/src/main/resources/init.sql @@ -27,7 +27,6 @@ CREATE TABLE moon_mission ); -- -- Lägger till data i tabellerna för Laboration 1. --- INSERT INTO account (password, first_name, last_name, ssn) VALUES ('8j_]xrCfh#t5,vne', 'Alexandra', 'Truby', '930213-1480'); INSERT INTO account (password, first_name, last_name, ssn)