diff --git a/src/main/java/nl/andrewlalis/Main.java b/src/main/java/nl/andrewlalis/Main.java index d036670..a1c4d51 100644 --- a/src/main/java/nl/andrewlalis/Main.java +++ b/src/main/java/nl/andrewlalis/Main.java @@ -1,5 +1,6 @@ package nl.andrewlalis; +import nl.andrewlalis.model.Organization; import nl.andrewlalis.model.database.Database; import nl.andrewlalis.ui.control.command.CommandExecutor; import nl.andrewlalis.ui.control.command.executables.ArchiveRepos; @@ -31,13 +32,17 @@ public class Main { // Command executor which will be used by all actions the user can do. CommandExecutor executor = new CommandExecutor(); + // Main application model. + Organization organization = new Organization(); + // Initialize User Interface. - InitializerApp app = new InitializerApp(executor); + InitializerApp app = new InitializerApp(executor, organization); app.begin(); app.setAccessToken(userOptions.get("token")); Database db = new Database("database/initializer.sqlite"); + executor.registerCommand("read_students", new ReadStudentsFileToDB(db)); executor.registerCommand("archive_all", new ArchiveRepos()); executor.registerCommand("generate_assignments", new GenerateAssignmentsRepo()); diff --git a/src/main/java/nl/andrewlalis/model/Organization.java b/src/main/java/nl/andrewlalis/model/Organization.java new file mode 100644 index 0000000..65d7a0a --- /dev/null +++ b/src/main/java/nl/andrewlalis/model/Organization.java @@ -0,0 +1,46 @@ +package nl.andrewlalis.model; + +import com.sun.org.apache.xpath.internal.operations.Or; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents the overarching model container for the entire application, and holds in memory all student + * teams created, teaching assistant teams, and any other state information that would be needed by the user interface + * or runtime executables. + */ +public class Organization { + + /** + * A list of all student teams in this organization. This is generated from a CSV file supplied after many students + * have filled in a Google form. + */ + private List studentTeams; + + /** + * Constructs a new Organization object with all instance variables initialized to empty values. + */ + public Organization() { + this.studentTeams = new ArrayList<>(); + } + + /** + * Determines if there are student teams available. + * @return True if there is at least one student team, or false otherwise. + */ + public boolean hasStudentTeams() { + return this.studentTeams.isEmpty(); + } + + // GETTERS + public List getStudentTeams() { + return this.studentTeams; + } + + // SETTERS + public void setStudentTeams(List teams) { + this.studentTeams = teams; + } + +} diff --git a/src/main/java/nl/andrewlalis/model/StudentTeam.java b/src/main/java/nl/andrewlalis/model/StudentTeam.java index 8967d27..7da57ff 100644 --- a/src/main/java/nl/andrewlalis/model/StudentTeam.java +++ b/src/main/java/nl/andrewlalis/model/StudentTeam.java @@ -1,5 +1,7 @@ package nl.andrewlalis.model; +import org.kohsuke.github.GHRepository; + import java.util.Arrays; /** @@ -7,6 +9,16 @@ import java.util.Arrays; */ public class StudentTeam extends Team{ + /** + * The repository belonging to this team. + */ + private GHRepository repository; + + /** + * The TATeam responsible for this student team. + */ + private TATeam taTeam; + public StudentTeam() { super(-1); } @@ -24,16 +36,19 @@ public class StudentTeam extends Team{ * A team is valid if and only if: * - The student count is equal to the team size. * - Each student is unique. - * - Each student's preferred partners match all the others. + * - Each student's preferred partners match all the others, or a student has no preferences. * @param teamSize The preferred size of teams. * @return True if the team is valid, and false otherwise. */ public boolean isValid(int teamSize) { if (this.memberCount() == teamSize) { for (Student studentA : this.getStudents()) { - for (Student studentB : this.getStudents()) { - if (!studentA.equals(studentB) && !studentA.getPreferredPartners().contains(studentB.getNumber())) { - return false; + // If the student doesn't have an preferred partners, then assume that this is valid. + if (!studentA.getPreferredPartners().isEmpty()) { + for (Student studentB : this.getStudents()) { + if (!studentA.equals(studentB) && !studentA.getPreferredPartners().contains(studentB.getNumber())) { + return false; + } } } } @@ -73,4 +88,20 @@ public class StudentTeam extends Team{ } return sb.toString(); } + + public GHRepository getRepository() { + return this.repository; + } + + public void setRepository(GHRepository repo) { + this.repository = repo; + } + + public TATeam getTaTeam() { + return this.taTeam; + } + + public void setTaTeam(TATeam team) { + this.taTeam = team; + } } diff --git a/src/main/java/nl/andrewlalis/model/database/Database.java b/src/main/java/nl/andrewlalis/model/database/Database.java index 5ac46e9..a62149d 100644 --- a/src/main/java/nl/andrewlalis/model/database/Database.java +++ b/src/main/java/nl/andrewlalis/model/database/Database.java @@ -82,7 +82,7 @@ public class Database { * @param personType The type of person to store, using a constant defined above. * @return True if successful, false otherwise. */ - private boolean storePerson(Person person, int personType) { + public boolean insertPerson(Person person, int personType) { try { logger.finest("Storing person: " + person); String sql = "INSERT INTO persons (id, name, email_address, github_username, person_type_id) VALUES (?, ?, ?, ?, ?);"; @@ -92,113 +92,31 @@ public class Database { stmt.setString(3, person.getEmailAddress()); stmt.setString(4, person.getGithubUsername()); stmt.setInt(5, personType); - stmt.execute(); - return true; + return stmt.execute(); } catch (SQLException e) { logger.severe("SQLException while inserting Person: " + person + '\n' + e.getMessage()); return false; } } - /** - * Stores a teaching assistant without a team. - * @param ta The teaching assistant to store. - * @return True if successful, false otherwise. - */ - public boolean storeTeachingAssistant(TeachingAssistant ta) { - return this.storeTeachingAssistant(ta, TEAM_NONE); - } - - /** - * Stores a teaching assistant in the database. - * @param ta The teaching assistant to store. - * @param teamId The teaching assistant's team id. - * @return True if successful, false otherwise. - */ - public boolean storeTeachingAssistant(TeachingAssistant ta, int teamId) { - if (!storePerson(ta, PERSON_TYPE_TA)) { - return false; - } - try { - String sql = "INSERT INTO teaching_assistants (person_id, team_id) VALUES (?, ?);"; - PreparedStatement stmt = this.connection.prepareStatement(sql); - stmt.setInt(1, ta.getNumber()); - stmt.setInt(2, teamId); - stmt.execute(); - return true; - } catch (SQLException e) { - logger.severe("SQL Exception while inserting TeachingAssistant.\n" + e.getMessage()); - e.printStackTrace(); - return false; - } - } - - /** - * Stores a team in the database. - * @param team The team to store. - * @param type The type of team that this is. - * @return True if successful, false otherwise. - */ - public boolean storeTeam(Team team, int type) { - try { - String sql = "INSERT INTO teams (id, team_type_id) VALUES (?, ?);"; - PreparedStatement stmt = this.connection.prepareStatement(sql); - stmt.setInt(1, team.getId()); - stmt.setInt(2, type); - stmt.execute(); - return true; - } catch (SQLException e) { - logger.severe("SQLException while inserting team: " + team + '\n' + e.getMessage()); - return false; - } - } - - /** - * Stores a list of student teams in the database. - * @param teams The list of teams to store. - * @return True if successful, or false if an error occurred. - */ - public boolean storeStudentTeams(List teams) { - for (StudentTeam team : teams) { - if (!this.storeTeam(team, TEAM_TYPE_STUDENT)) { - return false; - } - for (Student student : team.getStudents()) { - if (!this.storeStudent(student, team.getId())) { - return false; - } - } - } - return true; - } - - /** - * Stores a student without a team. - * @param student The student to store. - * @return True if successful, false otherwise. - */ - public boolean storeStudent(Student student) { - return this.storeStudent(student, TEAM_NONE); - } - /** * Stores a student in the database. * @param student The student to store. - * @param teamId The team id for the team the student is in. * @return True if the operation was successful, false otherwise. */ - public boolean storeStudent(Student student, int teamId) { + public boolean insertStudent(Student student) { logger.finest("Storing student: " + student); - if (!storePerson(student, PERSON_TYPE_STUDENT)) { + if (!insertPerson(student, PERSON_TYPE_STUDENT)) { return false; } try { - String sql = "INSERT INTO students (person_id, team_id, chose_partner) VALUES (?, ?, ?);"; + String sql = "INSERT INTO students (person_id, chose_partner) VALUES (?, ?);"; PreparedStatement stmt = this.connection.prepareStatement(sql); stmt.setInt(1, student.getNumber()); - stmt.setInt(2, teamId); - stmt.setInt(3, student.getPreferredPartners().size() > 0 ? 1 : 0); - stmt.execute(); + stmt.setInt(2, student.getPreferredPartners().size() > 0 ? 1 : 0); + if (!stmt.execute()) { + return false; + } // Storing partners. String sqlPartner = "INSERT INTO student_preferred_partners (student_id, partner_id) VALUES (?, ?);"; PreparedStatement stmtPartner = this.connection.prepareStatement(sqlPartner); @@ -215,6 +133,93 @@ public class Database { } } + /** + * Stores a teaching assistant in the database. + * @param ta The teaching assistant to store. + * @return True if successful, false otherwise. + */ + public boolean insertTeachingAssistant(TeachingAssistant ta) { + if (!insertPerson(ta, PERSON_TYPE_TA)) { + return false; + } + try { + String sql = "INSERT INTO teaching_assistants (person_id) VALUES (?);"; + PreparedStatement stmt = this.connection.prepareStatement(sql); + stmt.setInt(1, ta.getNumber()); + stmt.execute(); + return true; + } catch (SQLException e) { + logger.severe("SQL Exception while inserting TeachingAssistant.\n" + e.getMessage()); + e.printStackTrace(); + return false; + } + } + + /** + * Stores a team in the database, and any persons who do not yet exist. + * @param team The team to store. + * @param type The type of team that this is. + * @param personType The type of people that this team is made of. + * @return True if successful, false otherwise. + */ + public boolean insertTeam(Team team, int type, int personType) { + try { + String sql = "INSERT INTO teams (id, team_type_id) VALUES (?, ?);"; + PreparedStatement stmt = this.connection.prepareStatement(sql); + stmt.setInt(1, team.getId()); + stmt.setInt(2, type); + if (stmt.execute()) { + for (Person p : team.getMembers()) { + this.insertPerson(p, personType); + String sqlMembers = "INSERT INTO team_members (team_id, person_id) VALUES (?, ?);"; + PreparedStatement stmtMembers = this.connection.prepareStatement(sqlMembers); + stmtMembers.setInt(1, team.getId()); + stmtMembers.setInt(2, p.getNumber()); + stmtMembers.execute(); + } + } + return true; + } catch (SQLException e) { + logger.severe("SQLException while inserting team: " + team + '\n' + e.getMessage()); + return false; + } + } + + /** + * Stores a student team in the database. + * @param team The team to store. + * @return True if successful, false otherwise. + */ + public boolean insertStudentTeam(StudentTeam team) { + if (!this.insertTeam(team, TEAM_TYPE_STUDENT, PERSON_TYPE_STUDENT)) { + return false; + } + try { + String sql = "INSERT INTO student_teams (team_id, repository_name, teaching_assistant_team_id) VALUES (?, ?, ?);"; + PreparedStatement stmt = this.connection.prepareStatement(sql); + stmt.setInt(1, team.getId()); + stmt.setString(2, (team.getRepository() == null) ? null : team.getRepository().getName()); + stmt.setInt(3, (team.getTaTeam() == null) ? TEAM_NONE : team.getTaTeam().getId()); + return stmt.execute(); + } catch (SQLException e) { + logger.severe("SQLException while inserting student team: " + team + '\n' + e.getMessage()); + e.printStackTrace(); + return false; + } + } + + /** + * Stores a list of student teams in the database. + * @param teams The list of teams to store. + * @return True if successful, or false if an error occurred. + */ + public boolean storeStudentTeams(List teams) { + for (StudentTeam team : teams) { + this.insertStudentTeam(team); + } + return true; + } + /** * Retrieves a list of preferred partners that each student has set. * @param studentId The student id to search by. diff --git a/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java b/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java index c92e0f5..59155d4 100644 --- a/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java +++ b/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java @@ -1,11 +1,15 @@ package nl.andrewlalis.ui.view; +import com.sun.org.apache.xpath.internal.operations.Or; +import nl.andrewlalis.model.Organization; +import nl.andrewlalis.model.StudentTeam; import nl.andrewlalis.ui.control.OutputTextHandler; import nl.andrewlalis.ui.control.command.CommandExecutor; import nl.andrewlalis.ui.control.listeners.*; import javax.swing.*; import java.awt.*; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -37,8 +41,22 @@ public class InitializerApp extends JFrame { */ private CommandExecutor executor; - public InitializerApp(CommandExecutor executor) { + /** + * The organization object, which contains all important state information. + */ + private Organization organization; + + /** + * Constructs a new instance of the main application frame, with both an executor, and organization model. + * + * @param executor The command executor, which is passed to any action listeners, so that buttons in this interface + * may execute commands in the same way that the command line can. + * @param organization A reference to the application's organization model, which holds all important runtime state + * information. + */ + public InitializerApp(CommandExecutor executor, Organization organization) { this.executor = executor; + this.organization = organization; // UI initialization. ImageIcon icon = new ImageIcon(getClass().getResource("/image/icon.png")); diff --git a/src/main/resources/sql/table_init.sql b/src/main/resources/sql/table_init.sql index 9f0d8f2..0bba75d 100644 --- a/src/main/resources/sql/table_init.sql +++ b/src/main/resources/sql/table_init.sql @@ -43,7 +43,7 @@ CREATE TABLE IF NOT EXISTS teams ( ); CREATE TABLE IF NOT EXISTS team_members ( - id INTEGER PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, team_id INTEGER NOT NULL, person_id INTEGER NOT NULL, FOREIGN KEY (team_id) @@ -69,7 +69,6 @@ CREATE TABLE IF NOT EXISTS teaching_assistant_teams ( CREATE TABLE IF NOT EXISTS student_teams ( team_id INTEGER PRIMARY KEY, repository_name TEXT, - group_id INTEGER NOT NULL UNIQUE, teaching_assistant_team_id INTEGER, FOREIGN KEY (team_id) REFERENCES teams(id)