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. diff --git a/pom.xml b/pom.xml index 002ff66..09ebea1 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,11 @@ 5.20.0 + + org.slf4j + slf4j-nop + 2.0.17 + com.mysql mysql-connector-j diff --git a/src/main/java/com/example/AccountRepository.java b/src/main/java/com/example/AccountRepository.java new file mode 100644 index 0000000..2049241 --- /dev/null +++ b/src/main/java/com/example/AccountRepository.java @@ -0,0 +1,14 @@ +package com.example; + +public interface AccountRepository { + boolean login(String username, String password); + + long create(String first, String last, String ssn, String password); + + boolean updatePassword(int userId, String newPassword); + + boolean delete(int userId); + + boolean exists(int userId); + +} diff --git a/src/main/java/com/example/JdbcAccountRepository.java b/src/main/java/com/example/JdbcAccountRepository.java new file mode 100644 index 0000000..4297159 --- /dev/null +++ b/src/main/java/com/example/JdbcAccountRepository.java @@ -0,0 +1,108 @@ +package com.example; + +import javax.sql.DataSource; +import java.sql.*; + +public class JdbcAccountRepository implements AccountRepository { + + private final DataSource ds; + + public JdbcAccountRepository(DataSource ds) { + this.ds = ds; + } + + @Override + public boolean login(String username, String password) { + String sql = "SELECT 1 FROM account WHERE name = ? AND password = ?"; + + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + + ps.setString(1, username); + ps.setString(2, password); + + try (ResultSet rs = ps.executeQuery()) { + return rs.next(); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public long create(String first, String last, String ssn, String password) { + String sql = "INSERT INTO account(first_name, last_name, ssn, password) VALUES (?, ?, ?, ?)"; + + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + + ps.setString(1, first); + ps.setString(2, last); + ps.setString(3, ssn); + ps.setString(4, password); + + ps.executeUpdate(); + + ResultSet keys = ps.getGeneratedKeys(); + if (keys.next()) { + return keys.getLong(1); + } + throw new RuntimeException("No ID returned!"); + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @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) { + throw new RuntimeException(e); + } + } + + @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) { + throw new RuntimeException(e); + } + } + + @Override + public boolean exists(int userId) { + String sql = "SELECT 1 FROM account WHERE user_id = ?"; + + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + + ps.setInt(1, userId); + try (ResultSet rs = ps.executeQuery()) { + return rs.next(); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/com/example/JdbcMoonMissionRepository.java b/src/main/java/com/example/JdbcMoonMissionRepository.java new file mode 100644 index 0000000..c04b5ee --- /dev/null +++ b/src/main/java/com/example/JdbcMoonMissionRepository.java @@ -0,0 +1,77 @@ +package com.example; + +import javax.sql.DataSource; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class JdbcMoonMissionRepository implements MoonMissionRepository { + + private final DataSource ds; + + public JdbcMoonMissionRepository(DataSource ds) { + this.ds = ds; + } + + @Override + public List listSpacecraft() { + List list = new ArrayList<>(); + String sql = "SELECT spacecraft FROM moon_mission"; + + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql); + ResultSet rs = ps.executeQuery()) { + + while (rs.next()) { + list.add(rs.getString("spacecraft")); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + return list; + } + + @Override + public Mission getMissionById(long id) { + String sql = "SELECT mission_id, spacecraft FROM moon_mission WHERE mission_id = ?"; + + try (Connection conn = ds.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + + ps.setLong(1, id); + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return new Mission( + rs.getLong("mission_id"), + rs.getString("spacecraft") + ); + } + return null; + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public int countByYear(int year) { + String sql = "SELECT COUNT(*) AS total 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()) { + rs.next(); + return rs.getInt("total"); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 6dc6fbd..56ae151 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -1,11 +1,18 @@ package com.example; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; +import javax.sql.DataSource; +import java.io.IOException; +import java.sql.*; import java.util.Arrays; +import java.util.Scanner; public class Main { + public static final String RESET = "\u001B[0m"; + public static final String RED = "\u001B[31m"; + public static final String GREEN = "\u001B[32m"; + public static final String YELLOW = "\u001B[33m"; + public static final String BLUE = "\u001B[34m"; + static void main(String[] args) { if (isDevMode(args)) { @@ -26,13 +33,126 @@ public void run() { "as system properties (-Dkey=value) or environment variables."); } - try (Connection connection = DriverManager.getConnection(jdbcUrl, dbUser, dbPass)) { - } catch (SQLException e) { - throw new RuntimeException(e); - } + DataSource ds = new SimpleDriverManagerDataSource(jdbcUrl, dbUser, dbPass); + AccountRepository accountRepo = new JdbcAccountRepository(ds); + MoonMissionRepository missionRepo = new JdbcMoonMissionRepository(ds); + //Todo: Starting point for your code + Scanner sc = new Scanner(System.in); + + // Sign in + System.out.print("Enter username: "); + String username = sc.nextLine(); + System.out.println("Enter password: "); + String password = sc.nextLine(); + + boolean validLogin = accountRepo.login(username, password); + + if (!validLogin) { + System.out.println("Invalid username or password"); + return; + } + + System.out.println("Login successful!"); + + // Main menu + boolean isRunning = true; + + while (isRunning) { + printMenu(); + System.out.print("> "); + String option = sc.nextLine(); + + switch (option) { + case "1": + missionRepo.listSpacecraft().forEach(System.out::println); + break; + + case "2": + System.out.print("Enter ID: "); + long id = Long.parseLong(sc.nextLine()); + Mission m = missionRepo.getMissionById(id); + if (m == null) { + System.out.println("Mission not found"); + } else { + System.out.println("Mission ID: " + m.missionId); + System.out.println("Spacecraft: " + m.spacecraft); + } + break; + + case "3": + System.out.print("Enter year: "); + int year = Integer.parseInt(sc.nextLine()); + int count = missionRepo.countByYear(year); + System.out.println(count + " missions in year " + year); + break; + + case "4": + System.out.println("Enter your firstname: "); + String first = sc.nextLine(); + System.out.println("Enter your lastname: "); + String last = sc.nextLine(); + System.out.println("Enter your SSN: "); + String ssn = sc.nextLine(); + System.out.println("Enter your password: "); + String pw = sc.nextLine(); + + long newId = accountRepo.create(first, last, ssn, pw); + System.out.println("Account created successfully! User ID: " + newId); + break; + + case "5": + System.out.print("Enter your user ID: "); + int uid = Integer.parseInt(sc.nextLine()); + + // Check if account exists + if (!accountRepo.exists(uid)) { + System.out.println("Account not found!"); + break; + } + + // If exists --> create new passwrod + System.out.println("Enter your new password: "); + String newPw = sc.nextLine(); + + boolean updated = accountRepo.updatePassword(uid, newPw); + System.out.println(updated ? "Account updated!" : "Account not found!"); + + break; + + case "6": + System.out.print("Enter your user ID: "); + int delId = Integer.parseInt(sc.nextLine()); + boolean deleted = accountRepo.delete(delId); + System.out.println(deleted ? "Account deleted!" : "No account deleted."); + break; + + case "0": + isRunning = false; + break; + + default: + System.out.println("Invalid choice!"); + } + } + } + + + private void printMenu() { + System.out.println(BLUE + " " + RESET); + System.out.println(BLUE + "------MAIN MENU------" + RESET); + System.out.println(BLUE + "1. List moon missions" + RESET); + System.out.println(BLUE + "2. Get mission by ID" + RESET); + System.out.println(BLUE + "3. Count missions by year" + RESET); + System.out.println(BLUE + "4. Create account" + RESET); + System.out.println(BLUE + "5. Update account password" + RESET); + System.out.println(BLUE + "6. Delete account" + RESET); + System.out.println(BLUE + "0. Exit" + RESET); } + + + /** * Determines if the application is running in development mode based on system properties, * environment variables, or command-line arguments. diff --git a/src/main/java/com/example/Mission.java b/src/main/java/com/example/Mission.java new file mode 100644 index 0000000..8b34add --- /dev/null +++ b/src/main/java/com/example/Mission.java @@ -0,0 +1,11 @@ +package com.example; + +public class Mission { + public long missionId; + public String spacecraft; + + public Mission(long missionId, String spacecraft) { + this.missionId = missionId; + this.spacecraft = spacecraft; + } +} diff --git a/src/main/java/com/example/MoonMissionRepository.java b/src/main/java/com/example/MoonMissionRepository.java new file mode 100644 index 0000000..d424b0b --- /dev/null +++ b/src/main/java/com/example/MoonMissionRepository.java @@ -0,0 +1,9 @@ +package com.example; + +import java.util.List; + +public interface MoonMissionRepository { + List listSpacecraft(); + Mission getMissionById(long id); + int countByYear(int year); +} diff --git a/src/main/java/com/example/SimpleDriverManagerDataSource.java b/src/main/java/com/example/SimpleDriverManagerDataSource.java new file mode 100644 index 0000000..8c40c9c --- /dev/null +++ b/src/main/java/com/example/SimpleDriverManagerDataSource.java @@ -0,0 +1,36 @@ +package com.example; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class SimpleDriverManagerDataSource implements DataSource { + private final String url; + private final String user; + private final String password; + + public SimpleDriverManagerDataSource(String url, String user, String password) { + this.url = url; + this.user = user; + this.password = password; + } + + @Override + public Connection getConnection() throws SQLException { + return DriverManager.getConnection(url, user, password); + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + return DriverManager.getConnection(url, username, password); + } + + @Override public T unwrap(Class iface) { throw new UnsupportedOperationException(); } + @Override public boolean isWrapperFor(Class iface) { return false; } + @Override public java.io.PrintWriter getLogWriter() { return null; } + @Override public void setLogWriter(java.io.PrintWriter out) {} + @Override public void setLoginTimeout(int seconds) {} + @Override public int getLoginTimeout() { return 0; } + @Override public java.util.logging.Logger getParentLogger() { return null; } +} diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..32d03b1 --- /dev/null +++ b/todo.txt @@ -0,0 +1,65 @@ +1. When starting program: +Ask for: +- Username: +- Password: + +2. Checking if account exist in data table "account" + - if wrong - "Invalid username or password" -> program exit + - if OK - show menu + +3. Meny: + 1 = List moon missions + 2 = Get mission by id + 3 = Count missions for year + 4 = Create account + 5 = Update account password + 6 = Delete account + 0 = Exit + +After each choise program should run the function +Write the result or confirmation +Show menu again + +List +CHECK 1. Moon missions: +- Select from moon_mission +- Write name + +CHECK 2. Get Missions by Id +- Select spacecraft FROM moon_mission WHERE mission_id = ? +- Write mission id +- Spacecraft name + +CHECK 3. Count missions by year +- SELECT COUNT(*) FROM moon_missions WHERE launch_year = ? +- Write 3 missions in ? + +CHECK 4. Create Account +- Ask for: + - First name + - Last name + - SSN + - Password +- INSER INTO account(password, first_name, last_name, ssn) +VALUES (?,?,?,?) +- Write Account created + +CHECK 5. Update account password +- Ask for: + - user_id + - new password + +- UPDATE account SET password = ? WHERE user_id = ? +- Write Password updated + +CHECK 6. Delete account +- read: + - user_id +- Write Account deleted + +0. Exit +Exit program. + + +AngFra +MB=V4cbAqPz4vqmQ \ No newline at end of file