From 646d1564f9f52095a58a558df4c27889efccecf8 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:53:40 +0000 Subject: [PATCH 1/5] 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 66b030de8becc467200a4f3748a73ccd10619162 Mon Sep 17 00:00:00 2001 From: Jesper Larsson Date: Fri, 5 Dec 2025 15:44:32 +0100 Subject: [PATCH 2/5] basic login functionality Signed-off-by: Jesper Larsson --- src/main/java/com/example/Main.java | 53 ++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 6dc6fbd..5d275ef 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -1,8 +1,6 @@ package com.example; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; +import java.sql.*; import java.util.Arrays; public class Main { @@ -27,12 +25,59 @@ public void run() { } try (Connection connection = DriverManager.getConnection(jdbcUrl, dbUser, dbPass)) { + + boolean authorized = login(connection); + + if (authorized) { + promptMenu(); + } + else { + System.out.println("Username or password is invalid."); + System.exit(0); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + + + + } + + + private boolean login(Connection connection) { + String unm = IO.readln("Username: "); + String pw = IO.readln("Password: "); + + String accQuery = "select count(*) from account where binary name = ? and binary password = ?"; + try(PreparedStatement statement = connection.prepareStatement(accQuery)){ + statement.setString(1, unm); + statement.setString(2, pw); + + ResultSet rs = statement.executeQuery(); + while(rs.next()) { + if(rs.getInt("count(*)") == 1){return true;} + } + return false; } catch (SQLException e) { throw new RuntimeException(e); } - //Todo: Starting point for your code } + private int promptMenu(){ + System.out.print( + "1) List moon missions (prints spacecraft names from `moon_mission`).\n" + + "2) Get a moon mission by mission_id (prints details for that mission).\n" + + "3) Count missions for a given year (prompts: year; prints the number of missions launched that year).\n" + + "4) Create an account (prompts: first name, last name, ssn, password; prints confirmation).\n" + + "5) Update an account password (prompts: user_id, new password; prints confirmation).\n" + + "6) Delete an account (prompts: user_id; prints confirmation).\n" + + "0) Exit.\n"); + + return Integer.parseInt(IO.readln()); + } + + /** * Determines if the application is running in development mode based on system properties, * environment variables, or command-line arguments. From 6477a6216bd1f1dddb1555e0f2688f5b0c65316d Mon Sep 17 00:00:00 2001 From: Jesper Larsson Date: Wed, 10 Dec 2025 18:06:41 +0100 Subject: [PATCH 3/5] input and menu methods Signed-off-by: Jesper Larsson --- src/main/java/com/example/Main.java | 219 +++++++++++++++++++++++++++- 1 file changed, 211 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 5d275ef..5688698 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -2,6 +2,8 @@ import java.sql.*; import java.util.Arrays; +import java.util.Comparator; +import java.util.regex.Pattern; public class Main { @@ -28,20 +30,32 @@ public void run() { boolean authorized = login(connection); - if (authorized) { - promptMenu(); - } - else { + + if (!authorized){ System.out.println("Username or password is invalid."); System.exit(0); } + while(true) { + int option = promptMenu(); + + switch (option) { + case 1 -> listMissions(connection); + case 2 -> getMission(connection); + case 3 -> missionsCountYear(connection); + case 4 -> createAccount(connection); + case 5 -> System.out.println("5"); + case 6 -> System.out.println("6"); + case 0 -> System.exit(0); + + default -> System.out.println("Invalid choice.\n"); + } + } + } catch (SQLException e) { throw new RuntimeException(e); } - - } @@ -65,7 +79,7 @@ private boolean login(Connection connection) { } private int promptMenu(){ - System.out.print( + System.out.print("\n" + "1) List moon missions (prints spacecraft names from `moon_mission`).\n" + "2) Get a moon mission by mission_id (prints details for that mission).\n" + "3) Count missions for a given year (prompts: year; prints the number of missions launched that year).\n" + @@ -74,7 +88,196 @@ private int promptMenu(){ "6) Delete an account (prompts: user_id; prints confirmation).\n" + "0) Exit.\n"); - return Integer.parseInt(IO.readln()); + return getValidInt("Enter Choice: "); + } + + private void listMissions(Connection connection){ + String spaceshipQuery = "select spacecraft from moon_mission"; + + try(PreparedStatement statement = connection.prepareStatement(spaceshipQuery)){ + + ResultSet rs = statement.executeQuery(); + while(rs.next()) { + System.out.println(rs.getString("spacecraft")); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private void getMission(Connection connection){ + String missionQuery = "select * from moon_mission where mission_id = ?"; + int id = getValidInt("Mission Id: "); + + try(PreparedStatement statement = connection.prepareStatement(missionQuery)){ + statement.setInt(1, id); + + ResultSet rs = statement.executeQuery(); + + if(rs.next()) { + System.out.println( + "\nSpacecraft: " + rs.getString("spacecraft") + + "\nLaunch date: " + rs.getString("launch_date") + + "\nCarrier rocket: " + rs.getString("carrier_rocket") + + "\nOperator: " + rs.getString("operator") + + "\nMission type: " + rs.getString("mission_type") + + "\nOutcome: " + rs.getString("outcome")); + } + else { + System.out.println("\nMission not found."); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private void missionsCountYear(Connection connection){ + String missionYearQuery = "select count(*) from moon_mission where year(launch_date) = ?)"; + int year = getValidInt("Mission Year: "); + + try(PreparedStatement statement = connection.prepareStatement(missionYearQuery)){ + statement.setInt(1, year); + + ResultSet rs = statement.executeQuery(); + + while(rs.next()) { + System.out.println("\nMissions in " + year + ": " + rs.getInt("count(*)")); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } + + private void createAccount(Connection connection) { + String fn = getValidName("First Name: "); + String ln = getValidName("Last Name: "); + String ssn = getValidSSN("SSN: "); + String pw = getValidPassword("Password: "); + + String accName; + if(fn.length() <= 3){ + if(ln.length() <= 3){ + accName = fn + ln; + } + else{ + accName = fn + ln.substring(0, 2); + } + } + else if(ln.length() <= 3){ + accName = fn.substring(0, 3) + ln; + } + else{ + accName = fn.substring(0, 3) + ln.substring(0, 3); + } + + String checkName = "select count(*) from account where name = ?"; + + while(true) { + try (PreparedStatement statement = connection.prepareStatement(checkName)) { + statement.setString(1, accName); + + ResultSet rs = statement.executeQuery(); + + + if(rs.next() && rs.getInt("count(*)") == 0){ + break; + } + else{ + accName = getValidName("Account Name: "); + } + + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + String newAccQuery = "insert into account values (0, ?, ?, ?, ?, ?)"; + + try (PreparedStatement statement = connection.prepareStatement(newAccQuery)) { + statement.setString(1, accName); + statement.setString(2, pw); + statement.setString(3, fn); + statement.setString(4, ln); + statement.setString(5, ssn); + + statement.executeUpdate(); + + + System.out.println("\nAccount created successfully."); + + + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } + + + private int getValidInt(String prompt){ + while(true){ + try { + int option = Integer.parseInt(IO.readln("\n" + prompt)); + + if (option >= 0) { + return option; + } + else { + System.out.println("Please enter a positive integer.\n"); + } + } + catch (NumberFormatException e){ + System.out.println("Please enter a valid integer\n"); + } + } + } + + private String getValidName(String prompt){ + while(true){ + String name = IO.readln("\n" + prompt).trim(); + + if (name.isBlank()) { + System.out.println("\nCannot be blank"); + } + else if(!Pattern.matches("^[a-zA-Z]+$", name)){ + System.out.println("\nMust only contain letters"); + } + else{ + return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase(); + } + } + } + + private String getValidSSN(String prompt){ + while(true){ + String ssn = IO.readln("\n" + prompt).trim(); + + if (ssn.isBlank()) { + System.out.println("\nCannot be blank"); + } + else if(!Pattern.matches("^\\d{6}-\\d{4}$", ssn)){ + System.out.println("\nMust follow pattern YYMMDD-XXXX"); + } + else { + return ssn; + } + } + } + + private String getValidPassword(String prompt){ + while(true){ + String pw = IO.readln("\n" + prompt); + + if(pw.length() < 6){ + System.out.println("Password must be at least 6 characters"); + } + else{ + return pw; + } + } } From fbbfc416b80ecb3143dd156b2e0cdcb7434b0705 Mon Sep 17 00:00:00 2001 From: Jesper Larsson Date: Thu, 11 Dec 2025 13:17:13 +0100 Subject: [PATCH 4/5] basic functionality for all menu options Signed-off-by: Jesper Larsson --- src/main/java/com/example/Main.java | 48 ++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index 5688698..d415110 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -32,7 +32,7 @@ public void run() { if (!authorized){ - System.out.println("Username or password is invalid."); + System.out.println("Invalid username or password"); System.exit(0); } @@ -44,8 +44,8 @@ public void run() { case 2 -> getMission(connection); case 3 -> missionsCountYear(connection); case 4 -> createAccount(connection); - case 5 -> System.out.println("5"); - case 6 -> System.out.println("6"); + case 5 -> updatePassword(connection); + case 6 -> deleteAccount(connection); case 0 -> System.exit(0); default -> System.out.println("Invalid choice.\n"); @@ -207,7 +207,7 @@ else if(ln.length() <= 3){ statement.executeUpdate(); - System.out.println("\nAccount created successfully."); + System.out.println("\nAccount created"); } catch (SQLException e) { @@ -216,6 +216,46 @@ else if(ln.length() <= 3){ } + private void updatePassword (Connection connection) { + int id = getValidInt("User id: "); + String newPassword = getValidPassword("New password: "); + + String updatePwQuery = "update account set password = ? where id = ?"; + + try (PreparedStatement statement = connection.prepareStatement(updatePwQuery)) { + statement.setInt(1, id); + statement.setString(2, newPassword); + + statement.executeUpdate(); + + + System.out.println("\nPassword updated"); + + + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } + + private void deleteAccount(Connection connection) { + int id = getValidInt("User id: "); + + String deleteAccQuery = "delete from account where id = ?"; + + try (PreparedStatement statement = connection.prepareStatement(deleteAccQuery)) { + statement.setInt(1, id); + + statement.executeUpdate(); + + + System.out.println("\nAccount deleted"); + + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } private int getValidInt(String prompt){ while(true){ From 16d6c4234aaac509d7f7bb284dcf6c717d42874b Mon Sep 17 00:00:00 2001 From: Jesper Larsson Date: Thu, 11 Dec 2025 15:50:32 +0100 Subject: [PATCH 5/5] test green, not optimized or commented Signed-off-by: Jesper Larsson --- src/main/java/com/example/Main.java | 64 ++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java index d415110..2342385 100644 --- a/src/main/java/com/example/Main.java +++ b/src/main/java/com/example/Main.java @@ -3,10 +3,13 @@ import java.sql.*; import java.util.Arrays; import java.util.Comparator; +import java.util.Scanner; import java.util.regex.Pattern; public class Main { + Scanner scanner = new Scanner(System.in); + static void main(String[] args) { if (isDevMode(args)) { DevDatabaseInitializer.start(); @@ -28,14 +31,28 @@ public void run() { try (Connection connection = DriverManager.getConnection(jdbcUrl, dbUser, dbPass)) { - boolean authorized = login(connection); + while(true) { + //Scanner scanner = new Scanner(System.in); + boolean authorized = login(connection); + + if (!authorized) { + System.out.println("Invalid username or password"); + System.out.println("press 0 to exit"); + while(true){ + String exit = scanner.nextLine().trim(); + if(exit.equals("0")){ + return; + } + } - if (!authorized){ - System.out.println("Invalid username or password"); - System.exit(0); + } + else{ + break; + } } + while(true) { int option = promptMenu(); @@ -46,7 +63,9 @@ public void run() { case 4 -> createAccount(connection); case 5 -> updatePassword(connection); case 6 -> deleteAccount(connection); - case 0 -> System.exit(0); + case 0 -> { + return; + } default -> System.out.println("Invalid choice.\n"); } @@ -60,8 +79,10 @@ public void run() { private boolean login(Connection connection) { - String unm = IO.readln("Username: "); - String pw = IO.readln("Password: "); + System.out.println("Username: "); + String unm = scanner.nextLine(); + System.out.println("Password: "); + String pw = scanner.nextLine(); String accQuery = "select count(*) from account where binary name = ? and binary password = ?"; try(PreparedStatement statement = connection.prepareStatement(accQuery)){ @@ -133,7 +154,7 @@ private void getMission(Connection connection){ } private void missionsCountYear(Connection connection){ - String missionYearQuery = "select count(*) from moon_mission where year(launch_date) = ?)"; + String missionYearQuery = "select count(*) from moon_mission where year(launch_date) = ?"; int year = getValidInt("Mission Year: "); try(PreparedStatement statement = connection.prepareStatement(missionYearQuery)){ @@ -220,28 +241,27 @@ private void updatePassword (Connection connection) { int id = getValidInt("User id: "); String newPassword = getValidPassword("New password: "); - String updatePwQuery = "update account set password = ? where id = ?"; + String updatePwQuery = "update account set password = ? where user_id = ?"; try (PreparedStatement statement = connection.prepareStatement(updatePwQuery)) { - statement.setInt(1, id); - statement.setString(2, newPassword); + statement.setString(1, newPassword); + statement.setInt(2, id); statement.executeUpdate(); - - System.out.println("\nPassword updated"); - + System.out.println("updated"); } catch (SQLException e) { throw new RuntimeException(e); } + } private void deleteAccount(Connection connection) { int id = getValidInt("User id: "); - String deleteAccQuery = "delete from account where id = ?"; + String deleteAccQuery = "delete from account where user_id = ?"; try (PreparedStatement statement = connection.prepareStatement(deleteAccQuery)) { statement.setInt(1, id); @@ -249,7 +269,7 @@ private void deleteAccount(Connection connection) { statement.executeUpdate(); - System.out.println("\nAccount deleted"); + System.out.println("deleted"); } catch (SQLException e) { @@ -260,7 +280,8 @@ private void deleteAccount(Connection connection) { private int getValidInt(String prompt){ while(true){ try { - int option = Integer.parseInt(IO.readln("\n" + prompt)); + System.out.println("\n" + prompt); + int option = Integer.parseInt(scanner.nextLine()); if (option >= 0) { return option; @@ -277,7 +298,8 @@ private int getValidInt(String prompt){ private String getValidName(String prompt){ while(true){ - String name = IO.readln("\n" + prompt).trim(); + System.out.println("\n" + prompt); + String name = scanner.nextLine().trim(); if (name.isBlank()) { System.out.println("\nCannot be blank"); @@ -293,7 +315,8 @@ else if(!Pattern.matches("^[a-zA-Z]+$", name)){ private String getValidSSN(String prompt){ while(true){ - String ssn = IO.readln("\n" + prompt).trim(); + System.out.println("\n" + prompt); + String ssn = scanner.nextLine().trim(); if (ssn.isBlank()) { System.out.println("\nCannot be blank"); @@ -309,7 +332,8 @@ else if(!Pattern.matches("^\\d{6}-\\d{4}$", ssn)){ private String getValidPassword(String prompt){ while(true){ - String pw = IO.readln("\n" + prompt); + System.out.println("\n" + prompt); + String pw = scanner.nextLine(); if(pw.length() < 6){ System.out.println("Password must be at least 6 characters");