diff --git a/README.md b/README.md
index d20aaf9..7071577 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+[](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