From f39f5da40783301a9651cb9cf3f6fcff4e4343f0 Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Sun, 2 Sep 2018 10:07:39 +0200 Subject: [PATCH] Added ability to split up student teams amongst teaching assistant teams. --- .../nl/andrewlalis/git_api/GithubManager.java | 10 ++-- .../java/nl/andrewlalis/model/Person.java | 9 ++-- .../java/nl/andrewlalis/model/TATeam.java | 1 + .../executables/DelegateStudentTeams.java | 46 +++++++++++++++- .../executables/SetupStudentRepos.java | 24 +++++++++ .../DelegateStudentTeamsDialog.java | 54 +++++++++++++++++-- .../NumberIndicatorField.java | 2 +- .../TaTeamSpinner.java | 2 +- 8 files changed, 133 insertions(+), 15 deletions(-) create mode 100644 src/main/java/nl/andrewlalis/ui/control/command/executables/SetupStudentRepos.java rename src/main/java/nl/andrewlalis/ui/view/dialogs/{ => delegateStudentTeams}/DelegateStudentTeamsDialog.java (70%) rename src/main/java/nl/andrewlalis/ui/view/dialogs/{ => delegateStudentTeams}/NumberIndicatorField.java (93%) rename src/main/java/nl/andrewlalis/ui/view/dialogs/{ => delegateStudentTeams}/TaTeamSpinner.java (89%) diff --git a/src/main/java/nl/andrewlalis/git_api/GithubManager.java b/src/main/java/nl/andrewlalis/git_api/GithubManager.java index aa4c23f..8a4c67a 100644 --- a/src/main/java/nl/andrewlalis/git_api/GithubManager.java +++ b/src/main/java/nl/andrewlalis/git_api/GithubManager.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.logging.Logger; /** @@ -65,11 +66,12 @@ public class GithubManager { public List getTeams() { List teams = new ArrayList<>(); try { + Random rand = new Random(); for (Map.Entry entry : this.organization.getTeams().entrySet()) { - TATeam team = new TATeam(entry.getKey(), -1); + TATeam team = new TATeam(entry.getKey(), entry.getValue().getId()); team.setGithubTeam(entry.getValue()); - for (GHUser user : entry.getValue().getMembers()) { - team.addMember(new TeachingAssistant(-1, user.getName(), user.getEmail(), user.getLogin())); + for (GHUser user : entry.getValue().listMembers().asList()) { + team.addMember(new TeachingAssistant(rand.nextInt(), user.getName(), user.getEmail(), user.getLogin())); } teams.add(team); } @@ -135,7 +137,7 @@ public class GithubManager { * @param taTeam The team of teaching assistants that is responsible for these students. * @param prefix The prefix to append to the front of the repo name. */ - public void setupStudentTeam(StudentTeam team, TATeam taTeam, String prefix) { + public void setupStudentRepo(StudentTeam team, TATeam taTeam, String prefix) { // 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."); diff --git a/src/main/java/nl/andrewlalis/model/Person.java b/src/main/java/nl/andrewlalis/model/Person.java index 0c06a40..50b420a 100644 --- a/src/main/java/nl/andrewlalis/model/Person.java +++ b/src/main/java/nl/andrewlalis/model/Person.java @@ -83,10 +83,13 @@ public abstract class Person { return false; } Person p = (Person)o; + boolean emailSame = (p.getEmailAddress() != null && p.getEmailAddress().equals(this.getEmailAddress())); + boolean githubSame = (p.getGithubUsername() != null && p.getGithubUsername().equals(this.getGithubUsername())); + boolean nameSame = (p.getName() != null && p.getName().equalsIgnoreCase(this.getName())); return p.getNumber() == this.getNumber() - || p.getEmailAddress().equals(this.getEmailAddress()) - || p.getGithubUsername().equals(this.getGithubUsername()) - || p.getName().equalsIgnoreCase(this.getName()); + || emailSame + || githubSame + || nameSame; } /** diff --git a/src/main/java/nl/andrewlalis/model/TATeam.java b/src/main/java/nl/andrewlalis/model/TATeam.java index 02ad327..99dc211 100644 --- a/src/main/java/nl/andrewlalis/model/TATeam.java +++ b/src/main/java/nl/andrewlalis/model/TATeam.java @@ -35,6 +35,7 @@ public class TATeam extends Team { public TATeam(String name, int id) { super(id); this.name = name; + this.studentTeams = new ArrayList<>(); } /** diff --git a/src/main/java/nl/andrewlalis/ui/control/command/executables/DelegateStudentTeams.java b/src/main/java/nl/andrewlalis/ui/control/command/executables/DelegateStudentTeams.java index 150fd84..414f92f 100644 --- a/src/main/java/nl/andrewlalis/ui/control/command/executables/DelegateStudentTeams.java +++ b/src/main/java/nl/andrewlalis/ui/control/command/executables/DelegateStudentTeams.java @@ -1,8 +1,17 @@ package nl.andrewlalis.ui.control.command.executables; import nl.andrewlalis.git_api.GithubManager; +import nl.andrewlalis.model.StudentTeam; +import nl.andrewlalis.model.TATeam; import nl.andrewlalis.ui.view.InitializerApp; -import nl.andrewlalis.ui.view.dialogs.DelegateStudentTeamsDialog; +import nl.andrewlalis.ui.view.dialogs.delegateStudentTeams.DelegateStudentTeamsDialog; + +import javax.swing.*; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.concurrent.ThreadLocalRandom; +import java.util.logging.Logger; /** * An executable which opens up a dialog to allow a user to delegate how many student teams each TATeam gets to manage, @@ -15,14 +24,49 @@ public class DelegateStudentTeams extends GithubExecutable { */ private InitializerApp app; + /** + * The logger for outputting debug info. + */ + private static final Logger logger = Logger.getLogger(DelegateStudentTeams.class.getName()); + static { + logger.setParent(Logger.getGlobal()); + } + public DelegateStudentTeams(InitializerApp app) { this.app = app; } @Override protected boolean executeWithManager(GithubManager manager, String[] args) { + if (InitializerApp.organization.getStudentTeams().isEmpty()) { + JOptionPane.showMessageDialog(this.app, "There are no student teams! Please read some from a CSV file first.", "No Student Teams", JOptionPane.ERROR_MESSAGE); + return false; + } DelegateStudentTeamsDialog dialog = new DelegateStudentTeamsDialog(this.app, manager); dialog.begin(); + + if (dialog.isSuccessful()) { + Map results = dialog.getResult(); + List teams = InitializerApp.organization.getStudentTeams(); + int initialTeamsSize = teams.size(); + Stack teamsStack = new Stack<>(); + // Randomize the ordering of the student teams here. + for (int i = 0; i < initialTeamsSize; i++) { + teamsStack.push(teams.remove(ThreadLocalRandom.current().nextInt(0, teams.size()))); + } + + for (Map.Entry entry : results.entrySet()) { + TATeam team = entry.getKey(); + logger.fine("Team: " + team.getName() + " has " + entry.getValue() + " student teams."); + for (int i = 0; i < entry.getValue(); i++) { + team.addStudentTeam(teamsStack.pop()); + } + InitializerApp.organization.getTaTeams().add(team); + } + } else { + return false; + } + return true; } diff --git a/src/main/java/nl/andrewlalis/ui/control/command/executables/SetupStudentRepos.java b/src/main/java/nl/andrewlalis/ui/control/command/executables/SetupStudentRepos.java new file mode 100644 index 0000000..140c6e2 --- /dev/null +++ b/src/main/java/nl/andrewlalis/ui/control/command/executables/SetupStudentRepos.java @@ -0,0 +1,24 @@ +package nl.andrewlalis.ui.control.command.executables; + +import nl.andrewlalis.git_api.GithubManager; +import nl.andrewlalis.model.StudentTeam; +import nl.andrewlalis.model.TATeam; +import nl.andrewlalis.ui.view.InitializerApp; + +import java.util.List; + +public class SetupStudentRepos extends GithubExecutable { + @Override + protected boolean executeWithManager(GithubManager manager, String[] args) { + if (args.length < 1) { + return false; + } + List taTeams = InitializerApp.organization.getTaTeams(); + for (TATeam team : taTeams) { + for (StudentTeam studentTeam : team.getStudentTeams()) { + manager.setupStudentRepo(studentTeam, team, args[0]); + } + } + return true; + } +} diff --git a/src/main/java/nl/andrewlalis/ui/view/dialogs/DelegateStudentTeamsDialog.java b/src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/DelegateStudentTeamsDialog.java similarity index 70% rename from src/main/java/nl/andrewlalis/ui/view/dialogs/DelegateStudentTeamsDialog.java rename to src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/DelegateStudentTeamsDialog.java index 9589926..a4499de 100644 --- a/src/main/java/nl/andrewlalis/ui/view/dialogs/DelegateStudentTeamsDialog.java +++ b/src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/DelegateStudentTeamsDialog.java @@ -1,14 +1,13 @@ -package nl.andrewlalis.ui.view.dialogs; +package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams; import nl.andrewlalis.git_api.GithubManager; -import nl.andrewlalis.model.StudentTeam; import nl.andrewlalis.model.TATeam; import nl.andrewlalis.ui.view.InitializerApp; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -40,6 +39,11 @@ public class DelegateStudentTeamsDialog extends JDialog { */ private final int totalStudentTeamsCount; + /** + * A variable used to check if the result of this dialog was successful. + */ + private boolean successful; + public DelegateStudentTeamsDialog(InitializerApp parentApp, GithubManager manager) { super(parentApp, "Delegate Student Teams", true); this.manager = manager; @@ -64,6 +68,7 @@ public class DelegateStudentTeamsDialog extends JDialog { JPanel mainPanel = new JPanel(new BorderLayout()); mainPanel.add(this.generateTopPanel(), BorderLayout.NORTH); mainPanel.add(this.generateSpinnersPanel(), BorderLayout.CENTER); + mainPanel.add(this.generateSubmitPanel(), BorderLayout.SOUTH); this.setContentPane(mainPanel); this.pack(); @@ -92,6 +97,12 @@ public class DelegateStudentTeamsDialog extends JDialog { return spinnersPanel; } + /** + * Generates a panel containing a label and JSpinner for a particular TATeam. Also adds a change listener which + * makes sure that the total number of student teams given to TATeams never exceeds the total. + * @param team The team to link to this panel. + * @return The JPanel created. + */ private JPanel generateTeamSpinnerPanel(TATeam team) { JPanel panel = new JPanel(new BorderLayout()); JLabel teamLabel = new JLabel(team.getName()); @@ -105,7 +116,7 @@ public class DelegateStudentTeamsDialog extends JDialog { studentTeamsMatched += (int)teamSpinner.getValue(); } if (this.totalStudentTeamsCount - studentTeamsMatched < 0) { - s.setValue((int)s.getValue() + 1); // TODO: FIX! Causes stack overflow. + s.setValue(s.getPreviousValue()); } else { this.unmatchedStudentsCounter.setValue(this.totalStudentTeamsCount - studentTeamsMatched); } @@ -115,6 +126,39 @@ public class DelegateStudentTeamsDialog extends JDialog { return panel; } + /** + * Creates the panel at the bottom of the dialog which shows the 'okay' and 'cancel' buttons. + * @return The JPanel created. + */ + private JPanel generateSubmitPanel() { + JPanel panel = new JPanel(); + JButton okayButton = new JButton("Okay"); + okayButton.addActionListener(actionEvent -> { + if (unmatchedStudentsCounter.getValue() > 0) { + JOptionPane.showMessageDialog(getParent(), "There are still teams remaining!", "Not all teams assigned.", JOptionPane.INFORMATION_MESSAGE); + } else { + successful = true; + dispose(); + } + }); + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(actionEvent -> { + successful = false; + dispose(); + }); + panel.add(okayButton); + panel.add(cancelButton); + return panel; + } + + /** + * Determines if the user successfully delegated all student teams to TATeams. + * @return True if every student team is (theoretically) matched to a TATeam. + */ + public boolean isSuccessful() { + return this.successful; + } + /** * Gets a map containing an integer value for every TA team, which represents the number of student teams they will * be responsible for. diff --git a/src/main/java/nl/andrewlalis/ui/view/dialogs/NumberIndicatorField.java b/src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/NumberIndicatorField.java similarity index 93% rename from src/main/java/nl/andrewlalis/ui/view/dialogs/NumberIndicatorField.java rename to src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/NumberIndicatorField.java index 5e7a5d8..0fe7e3f 100644 --- a/src/main/java/nl/andrewlalis/ui/view/dialogs/NumberIndicatorField.java +++ b/src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/NumberIndicatorField.java @@ -1,4 +1,4 @@ -package nl.andrewlalis.ui.view.dialogs; +package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams; import javax.swing.*; diff --git a/src/main/java/nl/andrewlalis/ui/view/dialogs/TaTeamSpinner.java b/src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/TaTeamSpinner.java similarity index 89% rename from src/main/java/nl/andrewlalis/ui/view/dialogs/TaTeamSpinner.java rename to src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/TaTeamSpinner.java index 23e5c6e..3fcd13e 100644 --- a/src/main/java/nl/andrewlalis/ui/view/dialogs/TaTeamSpinner.java +++ b/src/main/java/nl/andrewlalis/ui/view/dialogs/delegateStudentTeams/TaTeamSpinner.java @@ -1,4 +1,4 @@ -package nl.andrewlalis.ui.view.dialogs; +package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams; import nl.andrewlalis.model.TATeam;