Added ability to split up student teams amongst teaching assistant teams.

This commit is contained in:
Andrew Lalis 2018-09-02 10:07:39 +02:00
parent 7c6f2527c0
commit f39f5da407
8 changed files with 133 additions and 15 deletions

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
@ -65,11 +66,12 @@ public class GithubManager {
public List<TATeam> getTeams() { public List<TATeam> getTeams() {
List<TATeam> teams = new ArrayList<>(); List<TATeam> teams = new ArrayList<>();
try { try {
Random rand = new Random();
for (Map.Entry<String, GHTeam> entry : this.organization.getTeams().entrySet()) { for (Map.Entry<String, GHTeam> 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()); team.setGithubTeam(entry.getValue());
for (GHUser user : entry.getValue().getMembers()) { for (GHUser user : entry.getValue().listMembers().asList()) {
team.addMember(new TeachingAssistant(-1, user.getName(), user.getEmail(), user.getLogin())); team.addMember(new TeachingAssistant(rand.nextInt(), user.getName(), user.getEmail(), user.getLogin()));
} }
teams.add(team); teams.add(team);
} }
@ -135,7 +137,7 @@ public class GithubManager {
* @param taTeam The team of teaching assistants that is responsible for these students. * @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. * @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. // First check that the assignments repo exists, otherwise no invitations can be sent.
if (this.assignmentsRepo == null) { if (this.assignmentsRepo == null) {
logger.warning("Assignments repository must be created before student repositories."); logger.warning("Assignments repository must be created before student repositories.");

View File

@ -83,10 +83,13 @@ public abstract class Person {
return false; return false;
} }
Person p = (Person)o; 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() return p.getNumber() == this.getNumber()
|| p.getEmailAddress().equals(this.getEmailAddress()) || emailSame
|| p.getGithubUsername().equals(this.getGithubUsername()) || githubSame
|| p.getName().equalsIgnoreCase(this.getName()); || nameSame;
} }
/** /**

View File

@ -35,6 +35,7 @@ public class TATeam extends Team {
public TATeam(String name, int id) { public TATeam(String name, int id) {
super(id); super(id);
this.name = name; this.name = name;
this.studentTeams = new ArrayList<>();
} }
/** /**

View File

@ -1,8 +1,17 @@
package nl.andrewlalis.ui.control.command.executables; package nl.andrewlalis.ui.control.command.executables;
import nl.andrewlalis.git_api.GithubManager; 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.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, * 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; 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) { public DelegateStudentTeams(InitializerApp app) {
this.app = app; this.app = app;
} }
@Override @Override
protected boolean executeWithManager(GithubManager manager, String[] args) { 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); DelegateStudentTeamsDialog dialog = new DelegateStudentTeamsDialog(this.app, manager);
dialog.begin(); dialog.begin();
if (dialog.isSuccessful()) {
Map<TATeam, Integer> results = dialog.getResult();
List<StudentTeam> teams = InitializerApp.organization.getStudentTeams();
int initialTeamsSize = teams.size();
Stack<StudentTeam> 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<TATeam, Integer> 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; return true;
} }

View File

@ -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<TATeam> taTeams = InitializerApp.organization.getTaTeams();
for (TATeam team : taTeams) {
for (StudentTeam studentTeam : team.getStudentTeams()) {
manager.setupStudentRepo(studentTeam, team, args[0]);
}
}
return true;
}
}

View File

@ -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.git_api.GithubManager;
import nl.andrewlalis.model.StudentTeam;
import nl.andrewlalis.model.TATeam; import nl.andrewlalis.model.TATeam;
import nl.andrewlalis.ui.view.InitializerApp; import nl.andrewlalis.ui.view.InitializerApp;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -40,6 +39,11 @@ public class DelegateStudentTeamsDialog extends JDialog {
*/ */
private final int totalStudentTeamsCount; 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) { public DelegateStudentTeamsDialog(InitializerApp parentApp, GithubManager manager) {
super(parentApp, "Delegate Student Teams", true); super(parentApp, "Delegate Student Teams", true);
this.manager = manager; this.manager = manager;
@ -64,6 +68,7 @@ public class DelegateStudentTeamsDialog extends JDialog {
JPanel mainPanel = new JPanel(new BorderLayout()); JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(this.generateTopPanel(), BorderLayout.NORTH); mainPanel.add(this.generateTopPanel(), BorderLayout.NORTH);
mainPanel.add(this.generateSpinnersPanel(), BorderLayout.CENTER); mainPanel.add(this.generateSpinnersPanel(), BorderLayout.CENTER);
mainPanel.add(this.generateSubmitPanel(), BorderLayout.SOUTH);
this.setContentPane(mainPanel); this.setContentPane(mainPanel);
this.pack(); this.pack();
@ -92,6 +97,12 @@ public class DelegateStudentTeamsDialog extends JDialog {
return spinnersPanel; 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) { private JPanel generateTeamSpinnerPanel(TATeam team) {
JPanel panel = new JPanel(new BorderLayout()); JPanel panel = new JPanel(new BorderLayout());
JLabel teamLabel = new JLabel(team.getName()); JLabel teamLabel = new JLabel(team.getName());
@ -105,7 +116,7 @@ public class DelegateStudentTeamsDialog extends JDialog {
studentTeamsMatched += (int)teamSpinner.getValue(); studentTeamsMatched += (int)teamSpinner.getValue();
} }
if (this.totalStudentTeamsCount - studentTeamsMatched < 0) { if (this.totalStudentTeamsCount - studentTeamsMatched < 0) {
s.setValue((int)s.getValue() + 1); // TODO: FIX! Causes stack overflow. s.setValue(s.getPreviousValue());
} else { } else {
this.unmatchedStudentsCounter.setValue(this.totalStudentTeamsCount - studentTeamsMatched); this.unmatchedStudentsCounter.setValue(this.totalStudentTeamsCount - studentTeamsMatched);
} }
@ -115,6 +126,39 @@ public class DelegateStudentTeamsDialog extends JDialog {
return panel; 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 * Gets a map containing an integer value for every TA team, which represents the number of student teams they will
* be responsible for. * be responsible for.

View File

@ -1,4 +1,4 @@
package nl.andrewlalis.ui.view.dialogs; package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams;
import javax.swing.*; import javax.swing.*;

View File

@ -1,4 +1,4 @@
package nl.andrewlalis.ui.view.dialogs; package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams;
import nl.andrewlalis.model.TATeam; import nl.andrewlalis.model.TATeam;