diff --git a/src/main/java/nl/andrewlalis/Main.java b/src/main/java/nl/andrewlalis/Main.java index 681ac2d..b6e7202 100644 --- a/src/main/java/nl/andrewlalis/Main.java +++ b/src/main/java/nl/andrewlalis/Main.java @@ -7,6 +7,7 @@ import nl.andrewlalis.model.StudentTeam; import nl.andrewlalis.ui.control.command.CommandExecutor; import nl.andrewlalis.ui.control.command.Executable; import nl.andrewlalis.ui.control.command.executables.ArchiveRepos; +import nl.andrewlalis.ui.control.command.executables.GenerateAssignmentsRepo; import nl.andrewlalis.ui.control.command.executables.ReadStudentsFileToDB; import nl.andrewlalis.ui.view.InitializerApp; import nl.andrewlalis.util.CommandLine; @@ -50,12 +51,9 @@ public class Main { Database db = new Database("database/initializer.sqlite"); db.initialize(); - executor.registerCommand("test", args1 -> { - System.out.println("TESTING"); - return true; - }); executor.registerCommand("readstudents", new ReadStudentsFileToDB(db)); executor.registerCommand("archiveall", new ArchiveRepos()); + executor.registerCommand("generateassignments", new GenerateAssignmentsRepo()); logger.info("GithubManager for Github Repositories in Educational Organizations. Program initialized."); diff --git a/src/main/java/nl/andrewlalis/git_api/GithubManager.java b/src/main/java/nl/andrewlalis/git_api/GithubManager.java index d188e53..5de6ec7 100644 --- a/src/main/java/nl/andrewlalis/git_api/GithubManager.java +++ b/src/main/java/nl/andrewlalis/git_api/GithubManager.java @@ -48,6 +48,7 @@ public class GithubManager { this.github = GitHub.connectUsingOAuth(accessToken); this.organization = this.github.getOrganization(organizationName); } catch (IOException e) { + logger.severe("Unable to make a GithubManager with organization name: " + organizationName + " and access token: " + accessToken); e.printStackTrace(); } } @@ -69,14 +70,14 @@ public class GithubManager { * @throws Exception If an error occurs while initializing the github repositories. */ public void initializeGithubRepos(List studentTeams, TATeam teamAll, String assignmentsRepoName) throws Exception { - this.setupAssignmentsRepo(assignmentsRepoName, "fuck the police", teamAll); + this.setupAssignmentsRepo(assignmentsRepoName, "fuck the police", teamAll.getName()); StudentTeam t = new StudentTeam(); Student s = new Student(3050831, "Andrew Lalis", "andrewlalisofficial@gmail.com", "andrewlalis", null); t.addMember(s); t.setId(42); - this.setupStudentTeam(t, teamAll, "advoop_2018"); + this.setupStudentTeam(t, teamAll.getGithubTeam(), "advoop_2018"); // TODO: Finish this method. } @@ -84,10 +85,11 @@ public class GithubManager { * Sets up the organization's assignments repository, and grants permissions to all teaching assistants. * @param assignmentsRepoName The name of the assignments repository. * @param description The description of the repository. - * @param allTeachingAssistants A team consisting of all teaching assistants. + * @param allTeachingAssistants The name of the team consisting of all teaching assistants. * @throws IOException If an HTTP request failed. */ - public void setupAssignmentsRepo(String assignmentsRepoName, String description, TATeam allTeachingAssistants) throws IOException { + public void setupAssignmentsRepo(String assignmentsRepoName, String description, String allTeachingAssistants) throws IOException { + GHTeam team = this.organization.getTeamByName(allTeachingAssistants); // Check if the repository already exists. GHRepository existingRepo = this.organization.getRepository(assignmentsRepoName); if (existingRepo != null) { @@ -95,29 +97,18 @@ public class GithubManager { logger.fine("Deleted pre-existing assignments repository."); } - // Create the repository. - GHCreateRepositoryBuilder builder = this.organization.createRepository(assignmentsRepoName); - builder.description("Assignments repository for Advanced Object Oriented Programming"); - builder.wiki(false); - builder.issues(true); - builder.private_(false); // TODO: Make this true for production. - builder.team(allTeachingAssistants.getGithubTeam()); - builder.gitignoreTemplate("Java"); - this.assignmentsRepo = builder.create(); - logger.info("Created assignments repository."); - - this.assignmentsRepo = this.createRepository(assignmentsRepoName, allTeachingAssistants, description, false, true, false); + this.assignmentsRepo = this.createRepository(assignmentsRepoName, team, description, false, true, false); if (this.assignmentsRepo == null) { logger.severe("Could not create assignments repository."); return; } - this.protectMasterBranch(this.assignmentsRepo, allTeachingAssistants); + this.protectMasterBranch(this.assignmentsRepo, team); // Grant all teaching assistants write access. - allTeachingAssistants.getGithubTeam().add(this.assignmentsRepo, GHOrganization.Permission.ADMIN); - logger.fine("Gave admin rights to all teaching assistants in team: " + allTeachingAssistants.getName()); + team.add(this.assignmentsRepo, GHOrganization.Permission.ADMIN); + logger.fine("Gave admin rights to all teaching assistants in team: " + team.getName()); } /** @@ -128,7 +119,7 @@ public class GithubManager { * @param prefix The prefix to append to the front of the repo name. * @throws IOException If an HTTP request fails. */ - public void setupStudentTeam(StudentTeam team, TATeam taTeam, String prefix) throws IOException { + public void setupStudentTeam(StudentTeam team, GHTeam taTeam, String prefix) throws IOException { // First check that the assignments repo exists, otherwise no invitations can be sent. if (this.assignmentsRepo == null) { logger.warning("Assignments repository must be created before student repositories."); @@ -145,7 +136,7 @@ public class GithubManager { this.protectMasterBranch(repo, taTeam); this.createDevelopmentBranch(repo); - taTeam.getGithubTeam().add(repo, GHOrganization.Permission.ADMIN); + taTeam.add(repo, GHOrganization.Permission.ADMIN); logger.fine("Added team " + taTeam.getName() + " as admin to repository: " + repo.getName()); List users = new ArrayList<>(); @@ -209,12 +200,12 @@ public class GithubManager { * @param team The team which gets admin rights to the master branch. */ @SuppressWarnings("deprecation") - private void protectMasterBranch(GHRepository repo, TATeam team) { + private void protectMasterBranch(GHRepository repo, GHTeam team) { try { GHBranchProtectionBuilder protectionBuilder = repo.getBranch("master").enableProtection(); protectionBuilder.includeAdmins(false); protectionBuilder.restrictPushAccess(); - protectionBuilder.teamPushAccess(team.getGithubTeam()); + protectionBuilder.teamPushAccess(team); protectionBuilder.addRequiredChecks("ci/circleci"); protectionBuilder.enable(); logger.fine("Protected master branch of repository: " + repo.getName()); @@ -249,10 +240,10 @@ public class GithubManager { * @param isPrivate Whether or not the repository is private. * @return The repository that was created, or */ - private GHRepository createRepository(String name, TATeam taTeam, String description, boolean hasWiki, boolean hasIssues, boolean isPrivate){ + private GHRepository createRepository(String name, GHTeam taTeam, String description, boolean hasWiki, boolean hasIssues, boolean isPrivate){ try { GHCreateRepositoryBuilder builder = this.organization.createRepository(name); - builder.team(taTeam.getGithubTeam()); + builder.team(taTeam); builder.wiki(hasWiki); builder.issues(hasIssues); builder.description(description); diff --git a/src/main/java/nl/andrewlalis/model/database/Database.java b/src/main/java/nl/andrewlalis/model/database/Database.java index 180124e..14c8626 100644 --- a/src/main/java/nl/andrewlalis/model/database/Database.java +++ b/src/main/java/nl/andrewlalis/model/database/Database.java @@ -3,6 +3,7 @@ package nl.andrewlalis.model.database; import nl.andrewlalis.model.*; import java.sql.*; +import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; @@ -99,22 +100,46 @@ public class Database { } } - private Student retrieveStudent(int id) { - + /** + * Retrieves a list of preferred partners that each student has set. + * @param studentId The student id to search by. + * @return A list of student id's for all students that the given student wishes to be their partner. + */ + private List retrievePreferredPartners(int studentId) { + try { + logger.finest("Retrieving preferred partners of student: " + studentId); + String sql = "SELECT partner_id FROM student_preferred_partners WHERE student_id=?;"; + PreparedStatement stmt = this.connection.prepareStatement(sql); + stmt.setInt(1, studentId); + ResultSet results = stmt.executeQuery(); + List partners = new ArrayList<>(); + while (results.next()) { + partners.add(results.getInt(1)); + } + return partners; + } catch (SQLException e) { + logger.severe("SQL Exception while retrieving preferred partners of student: " + studentId + '\n' + e.getMessage()); + e.printStackTrace(); + return new ArrayList<>(); + } } - private Person retrievePerson(int id) { + /** + * Retrieves a student by their id. + * @param id The id of the student (student number) + * @return The student corresponding to this number, or null if it could not be found. + */ + public Student retrieveStudent(int id) { try { - logger.finest("Retrieving person (id=" + id + ")."); String sql = "SELECT * FROM persons WHERE id=?"; PreparedStatement stmt = this.connection.prepareStatement(sql); stmt.setInt(1, id); ResultSet result = stmt.executeQuery(); - Person p = new Person(id, result.getString("name"), result.getString("email_address"), result.getString("github_username")); + return new Student(id, result.getString("name"), result.getString("email_address"), result.getString("github_username"), this.retrievePreferredPartners(id)); } catch (SQLException e) { - logger.severe("SQL Exception while retrieving Person.\n" + e.getMessage()); + logger.severe("SQL Exception while retrieving Student.\n" + e.getMessage()); e.printStackTrace(); - return false; + return null; } } @@ -217,6 +242,14 @@ public class Database { stmt.setInt(2, teamId); stmt.setInt(3, student.getPreferredPartners().size() > 0 ? 1 : 0); stmt.execute(); + // Storing partners. + String sqlPartner = "INSERT INTO student_preferred_partners (student_id, partner_id) VALUES (?, ?);"; + PreparedStatement stmtPartner = this.connection.prepareStatement(sqlPartner); + for (int partnerId : student.getPreferredPartners()) { + stmtPartner.setInt(1, student.getNumber()); + stmtPartner.setInt(2, partnerId); + stmtPartner.execute(); + } return true; } catch (SQLException e) { logger.severe("SQL Exception while inserting Student into database.\n" + e.getMessage()); diff --git a/src/main/java/nl/andrewlalis/ui/control/command/executables/GenerateAssignmentsRepo.java b/src/main/java/nl/andrewlalis/ui/control/command/executables/GenerateAssignmentsRepo.java index d09d887..2ccb06b 100644 --- a/src/main/java/nl/andrewlalis/ui/control/command/executables/GenerateAssignmentsRepo.java +++ b/src/main/java/nl/andrewlalis/ui/control/command/executables/GenerateAssignmentsRepo.java @@ -2,15 +2,29 @@ package nl.andrewlalis.ui.control.command.executables; import nl.andrewlalis.git_api.GithubManager; +import java.io.IOException; + /** * Generates the assignments repository, with the supplied github manager, as well as the following extra arguments: + * + * 1. The name of the repository. + * 2. Description of the repository. + * 3. Name of TA team containing all members. */ public class GenerateAssignmentsRepo extends GithubExecutable { @Override protected boolean executeWithManager(GithubManager manager, String[] args) { - - manager.setupAssignmentsRepo(args[0], args[1], ); + if (args.length < 3) { + return false; + } + try { + manager.setupAssignmentsRepo(args[0], args[1], args[2]); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } } } diff --git a/src/main/java/nl/andrewlalis/ui/control/listeners/GenerateAssignmentsRepoListener.java b/src/main/java/nl/andrewlalis/ui/control/listeners/GenerateAssignmentsRepoListener.java new file mode 100644 index 0000000..6143821 --- /dev/null +++ b/src/main/java/nl/andrewlalis/ui/control/listeners/GenerateAssignmentsRepoListener.java @@ -0,0 +1,36 @@ +package nl.andrewlalis.ui.control.listeners; + +import nl.andrewlalis.ui.control.command.CommandExecutor; +import nl.andrewlalis.ui.view.InitializerApp; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +/** + * Listens for when the user does an action to generate the assignments repository. + */ +public class GenerateAssignmentsRepoListener extends ExecutableListener { + + public GenerateAssignmentsRepoListener(CommandExecutor executor, InitializerApp app) { + super(executor, app); + } + + @Override + public void actionPerformed(ActionEvent actionEvent) { + String repoName = JOptionPane.showInputDialog(this.app, "Enter a name for the assignments repository.", "Repository Name", JOptionPane.QUESTION_MESSAGE); + if (repoName != null) { + String description = JOptionPane.showInputDialog(this.app, "Enter a description for the repository.", "Repository Description", JOptionPane.QUESTION_MESSAGE); + String teamName = JOptionPane.showInputDialog(this.app, "Enter the name of the TA team containing all teaching assistants.", "TA Team Name", JOptionPane.QUESTION_MESSAGE); + if (teamName != null) { + this.executor.executeCommand("generateassignments", new String[]{ + this.app.getOrganizationName(), + this.app.getAccessToken(), + repoName, + description, + teamName + }); + } + } + } + +} diff --git a/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java b/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java index e7384e5..2ff6c2a 100644 --- a/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java +++ b/src/main/java/nl/andrewlalis/ui/view/InitializerApp.java @@ -5,6 +5,7 @@ import nl.andrewlalis.ui.control.command.CommandExecutor; import nl.andrewlalis.ui.control.command.executables.ArchiveRepos; import nl.andrewlalis.ui.control.listeners.ArchiveAllListener; import nl.andrewlalis.ui.control.listeners.CommandFieldKeyListener; +import nl.andrewlalis.ui.control.listeners.GenerateAssignmentsRepoListener; import nl.andrewlalis.ui.control.listeners.ReadStudentsFileListener; import javax.swing.*; @@ -25,7 +26,7 @@ public class InitializerApp extends JFrame { /** * A default size of the window on startup. */ - private static final Dimension SIZE = new Dimension(800, 600); + private static final Dimension SIZE = new Dimension(1000, 600); /** * The pane on which general purpose program output is written. @@ -123,6 +124,10 @@ public class InitializerApp extends JFrame { generateStudentTeamsButton.addActionListener(new ReadStudentsFileListener(this.executor, this)); commonActionsPanel.add(generateStudentTeamsButton); + JButton generateAssignmentsRepoButton = new JButton("Generate Assignments Repo"); + generateAssignmentsRepoButton.addActionListener(new GenerateAssignmentsRepoListener(this.executor, this)); + commonActionsPanel.add(generateAssignmentsRepoButton); + githubManagerPanel.add(commonActionsPanel, BorderLayout.CENTER); return githubManagerPanel; diff --git a/src/main/resources/sql/table_init.sql b/src/main/resources/sql/table_init.sql index 2604917..e5ffa1d 100644 --- a/src/main/resources/sql/table_init.sql +++ b/src/main/resources/sql/table_init.sql @@ -73,6 +73,16 @@ CREATE TABLE IF NOT EXISTS students ( ON UPDATE CASCADE ); +CREATE TABLE IF NOT EXISTS student_preferred_partners ( + student_id INTEGER PRIMARY KEY, + partner_id INTEGER NOT NULL, + FOREIGN KEY (student_id) + REFERENCES students(person_id) + ON DELETE CASCADE + ON UPDATE CASCADE, + UNIQUE (student_id, partner_id) +); + CREATE TABLE IF NOT EXISTS teaching_assistants ( person_id INTEGER PRIMARY KEY, team_id INTEGER NOT NULL,