Adds more than just a TA dialog #4
			
				
			
		
		
		
	| 
						 | 
					@ -1,24 +1,12 @@
 | 
				
			||||||
package nl.andrewlalis;
 | 
					package nl.andrewlalis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import nl.andrewlalis.model.database.Database;
 | 
					 | 
				
			||||||
import nl.andrewlalis.git_api.GithubManager;
 | 
					 | 
				
			||||||
import nl.andrewlalis.model.Student;
 | 
					 | 
				
			||||||
import nl.andrewlalis.model.StudentTeam;
 | 
					 | 
				
			||||||
import nl.andrewlalis.ui.control.command.CommandExecutor;
 | 
					import nl.andrewlalis.ui.control.command.CommandExecutor;
 | 
				
			||||||
import nl.andrewlalis.ui.control.command.Executable;
 | 
					import nl.andrewlalis.ui.control.command.executables.*;
 | 
				
			||||||
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.ui.view.InitializerApp;
 | 
				
			||||||
import nl.andrewlalis.util.CommandLine;
 | 
					import nl.andrewlalis.util.CommandLine;
 | 
				
			||||||
import nl.andrewlalis.util.Logging;
 | 
					import nl.andrewlalis.util.Logging;
 | 
				
			||||||
import nl.andrewlalis.util.TeamGenerator;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.swing.*;
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					 | 
				
			||||||
import java.util.logging.Logger;
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -34,12 +22,7 @@ public class Main {
 | 
				
			||||||
        Map<String, String> userOptions = CommandLine.parseArgs(args);
 | 
					        Map<String, String> userOptions = CommandLine.parseArgs(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Initialize logger.
 | 
					        // Initialize logger.
 | 
				
			||||||
        try {
 | 
					        Logging.setup();
 | 
				
			||||||
            Logging.setup(true); // TODO: Replace true with command line arg.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        } catch (IOException e) {
 | 
					 | 
				
			||||||
            logger.severe("Unable to save log to file.");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Command executor which will be used by all actions the user can do.
 | 
					        // Command executor which will be used by all actions the user can do.
 | 
				
			||||||
        CommandExecutor executor = new CommandExecutor();
 | 
					        CommandExecutor executor = new CommandExecutor();
 | 
				
			||||||
| 
						 | 
					@ -47,37 +30,21 @@ public class Main {
 | 
				
			||||||
        // Initialize User Interface.
 | 
					        // Initialize User Interface.
 | 
				
			||||||
        InitializerApp app = new InitializerApp(executor);
 | 
					        InitializerApp app = new InitializerApp(executor);
 | 
				
			||||||
        app.begin();
 | 
					        app.begin();
 | 
				
			||||||
 | 
					        app.setAccessToken(userOptions.get("token"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Database db = new Database("database/initializer.sqlite");
 | 
					        // Initialize executable commands.
 | 
				
			||||||
        db.initialize();
 | 
					        executor.registerCommand("read_students", new ReadStudentsFile(app));
 | 
				
			||||||
 | 
					        executor.registerCommand("archive_all", new ArchiveRepos());
 | 
				
			||||||
 | 
					        executor.registerCommand("generate_assignments", new GenerateAssignmentsRepo());
 | 
				
			||||||
 | 
					        executor.registerCommand("define_ta_teams", new DefineTaTeams(app));
 | 
				
			||||||
 | 
					        executor.registerCommand("list_errors", new ListErrors(app));
 | 
				
			||||||
 | 
					        executor.registerCommand("delete_repos", new DeleteRepos());
 | 
				
			||||||
 | 
					        executor.registerCommand("delegate_student_teams", new DelegateStudentTeams(app));
 | 
				
			||||||
 | 
					        executor.registerCommand("setup_student_repos", new SetupStudentRepos(app));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        executor.registerCommand("readstudents", new ReadStudentsFileToDB(db));
 | 
					        logger.info("GithubManager for Github Repositories in Educational Organizations.\n" +
 | 
				
			||||||
        executor.registerCommand("archiveall", new ArchiveRepos());
 | 
					                "© Andrew Lalis (2018), All rights reserved.\n" +
 | 
				
			||||||
        executor.registerCommand("generateassignments", new GenerateAssignmentsRepo());
 | 
					                "Program initialized.");
 | 
				
			||||||
 | 
					 | 
				
			||||||
        logger.info("GithubManager for Github Repositories in Educational Organizations. Program initialized.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Get studentTeams from CSV file.
 | 
					 | 
				
			||||||
//        List<StudentTeam> studentTeams = getStudentTeamsFromCSV(userOptions.get("input"), Integer.parseInt(userOptions.get("teamsize")));
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//        GithubManager githubManager = new GithubManager(
 | 
					 | 
				
			||||||
//                userOptions.get("organization"),
 | 
					 | 
				
			||||||
//                userOptions.get("token"),
 | 
					 | 
				
			||||||
//                "assignments_2018",
 | 
					 | 
				
			||||||
//                "teaching-assistants",
 | 
					 | 
				
			||||||
//                "advoop_2018"
 | 
					 | 
				
			||||||
//        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            //githubManager.initializeGithubRepos(studentTeams);
 | 
					 | 
				
			||||||
            //githubManager.archiveAllRepositories("team");
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					 | 
				
			||||||
            e.printStackTrace();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 | 
				
			||||||
import nl.andrewlalis.model.Student;
 | 
					import nl.andrewlalis.model.Student;
 | 
				
			||||||
import nl.andrewlalis.model.StudentTeam;
 | 
					import nl.andrewlalis.model.StudentTeam;
 | 
				
			||||||
import nl.andrewlalis.model.TATeam;
 | 
					import nl.andrewlalis.model.TATeam;
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TeachingAssistant;
 | 
				
			||||||
import org.apache.http.HttpResponse;
 | 
					import org.apache.http.HttpResponse;
 | 
				
			||||||
import org.apache.http.client.methods.HttpPatch;
 | 
					import org.apache.http.client.methods.HttpPatch;
 | 
				
			||||||
import org.apache.http.entity.StringEntity;
 | 
					import org.apache.http.entity.StringEntity;
 | 
				
			||||||
| 
						 | 
					@ -15,6 +16,8 @@ import org.kohsuke.github.*;
 | 
				
			||||||
import java.io.IOException;
 | 
					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.Random;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -54,31 +57,43 @@ public class GithubManager {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Initializes the github repository for all studentTeams given.
 | 
					     * Gets a list of teams in the organization.
 | 
				
			||||||
     *
 | 
					     * @return A List of all TA teams in the organization.
 | 
				
			||||||
     * Creates for the entire organization:
 | 
					 | 
				
			||||||
     * - an assignments repository with protected master branch and TA permissions.
 | 
					 | 
				
			||||||
     * Creates for each team:
 | 
					 | 
				
			||||||
     * - a repository
 | 
					 | 
				
			||||||
     * - protected master branch
 | 
					 | 
				
			||||||
     * - development branch
 | 
					 | 
				
			||||||
     * - adds students to repository
 | 
					 | 
				
			||||||
     * - adds all students to assignments repository.
 | 
					 | 
				
			||||||
     * @param studentTeams The list of student studentTeams.
 | 
					 | 
				
			||||||
     * @param teamAll The team of all teaching assistants.
 | 
					 | 
				
			||||||
     * @param assignmentsRepoName The name of the assignments repo.
 | 
					 | 
				
			||||||
     * @throws Exception If an error occurs while initializing the github repositories.
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void initializeGithubRepos(List<StudentTeam> studentTeams, TATeam teamAll, String assignmentsRepoName) throws Exception {
 | 
					    public List<TATeam> getTeams() {
 | 
				
			||||||
        this.setupAssignmentsRepo(assignmentsRepoName, "fuck the police", teamAll.getName());
 | 
					        List<TATeam> teams = new ArrayList<>();
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Random rand = new Random();
 | 
				
			||||||
 | 
					            for (Map.Entry<String, GHTeam> entry : this.organization.getTeams().entrySet()) {
 | 
				
			||||||
 | 
					                TATeam team = new TATeam(entry.getKey(), entry.getValue().getId());
 | 
				
			||||||
 | 
					                team.setGithubTeam(entry.getValue());
 | 
				
			||||||
 | 
					                for (GHUser user : entry.getValue().listMembers().asList()) {
 | 
				
			||||||
 | 
					                    team.addMember(new TeachingAssistant(rand.nextInt(), user.getName(), user.getEmail(), user.getLogin()));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                teams.add(team);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            logger.severe("Could not get a list of teams in the organization.\n" + e.getMessage());
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return teams;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        StudentTeam t = new StudentTeam();
 | 
					    /**
 | 
				
			||||||
        Student s = new Student(3050831, "Andrew Lalis", "andrewlalisofficial@gmail.com", "andrewlalis", null);
 | 
					     * Gets a list of all teaching assistants, or members, in the organization.
 | 
				
			||||||
        t.addMember(s);
 | 
					     * @return A List of teaching assistants, and empty if an error occurred.
 | 
				
			||||||
        t.setId(42);
 | 
					     */
 | 
				
			||||||
 | 
					    public List<TeachingAssistant> getMembers() {
 | 
				
			||||||
        this.setupStudentTeam(t, teamAll.getGithubTeam(), "advoop_2018");
 | 
					        List<TeachingAssistant> teachingAssistants = new ArrayList<>();
 | 
				
			||||||
        // TODO: Finish this method.
 | 
					        try {
 | 
				
			||||||
 | 
					            for (GHUser member : this.organization.listMembers().asList()) {
 | 
				
			||||||
 | 
					                teachingAssistants.add(new TeachingAssistant(-1, member.getName(), member.getEmail(), member.getLogin()));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            logger.severe("Could not get list of members in the organization.\n" + e.getMessage());
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return teachingAssistants;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -97,7 +112,7 @@ public class GithubManager {
 | 
				
			||||||
            logger.fine("Deleted pre-existing assignments repository.");
 | 
					            logger.fine("Deleted pre-existing assignments repository.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.assignmentsRepo = this.createRepository(assignmentsRepoName, team, description, false, true, false);
 | 
					        this.assignmentsRepo = this.createRepository(assignmentsRepoName, team, description, false, true, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.assignmentsRepo == null) {
 | 
					        if (this.assignmentsRepo == null) {
 | 
				
			||||||
            logger.severe("Could not create assignments repository.");
 | 
					            logger.severe("Could not create assignments repository.");
 | 
				
			||||||
| 
						 | 
					@ -117,46 +132,46 @@ public class GithubManager {
 | 
				
			||||||
     * @param team The student team to set up.
 | 
					     * @param team The student team to set up.
 | 
				
			||||||
     * @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.
 | 
				
			||||||
     * @throws IOException If an HTTP request fails.
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void setupStudentTeam(StudentTeam team, GHTeam taTeam, String prefix) throws IOException {
 | 
					    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.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        GHRepository repo = this.createRepository(team.generateUniqueName(prefix), taTeam, team.generateRepoDescription(), false, true, false);
 | 
					        GHRepository repo = this.createRepository(team.generateUniqueName(prefix), taTeam.getGithubTeam(), team.generateRepoDescription(), false, true, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (repo == null) {
 | 
					        if (repo == null) {
 | 
				
			||||||
            logger.severe("Repository for student team " + team.getId() + " could not be created.");
 | 
					            logger.severe("Repository for student team " + team.getId() + " could not be created.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.protectMasterBranch(repo, taTeam);
 | 
					        this.protectMasterBranch(repo, taTeam.getGithubTeam());
 | 
				
			||||||
        this.createDevelopmentBranch(repo);
 | 
					        this.createDevelopmentBranch(repo);
 | 
				
			||||||
 | 
					        this.addTATeamAsAdmin(repo, taTeam.getGithubTeam());
 | 
				
			||||||
 | 
					        this.inviteStudentsToRepos(team, repo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        taTeam.add(repo, GHOrganization.Permission.ADMIN);
 | 
					        team.setRepository(repo);
 | 
				
			||||||
        logger.fine("Added team " + taTeam.getName() + " as admin to repository: " + repo.getName());
 | 
					        team.setTaTeam(taTeam);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        List<GHUser> users = new ArrayList<>();
 | 
					 | 
				
			||||||
        for (Student student : team.getStudents()) {
 | 
					 | 
				
			||||||
            GHUser user = this.github.getUser(student.getGithubUsername());
 | 
					 | 
				
			||||||
            users.add(user);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        repo.addCollaborators(users);
 | 
					 | 
				
			||||||
        this.assignmentsRepo.addCollaborators(users);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Deletes all repositories in the organization.
 | 
					     * Deletes all repositories in the organization.
 | 
				
			||||||
     * @throws IOException if an error occurs with sending requests.
 | 
					     * @param substring The substring which repository names should contain to be deleted.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void deleteAllRepositories() throws IOException {
 | 
					    public void deleteAllRepositories(String substring) {
 | 
				
			||||||
        List<GHRepository> repositories = this.organization.listRepositories().asList();
 | 
					        List<GHRepository> repositories = this.organization.listRepositories().asList();
 | 
				
			||||||
        for (GHRepository repo : repositories) {
 | 
					        for (GHRepository repo : repositories) {
 | 
				
			||||||
            repo.delete();
 | 
					            if (repo.getName().contains(substring)) {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    repo.delete();
 | 
				
			||||||
 | 
					                    logger.info("Deleted repository: " + repo.getName());
 | 
				
			||||||
 | 
					                } catch (IOException e) {
 | 
				
			||||||
 | 
					                    logger.severe("Could not delete repository: " + repo.getName());
 | 
				
			||||||
 | 
					                    e.printStackTrace();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,7 +179,7 @@ public class GithubManager {
 | 
				
			||||||
     * Archives all repositories whose name contains the given substring.
 | 
					     * Archives all repositories whose name contains the given substring.
 | 
				
			||||||
     * @param sub Any repository containing this substring will be archived.
 | 
					     * @param sub Any repository containing this substring will be archived.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void archiveAllRepositories(String sub) throws IOException {
 | 
					    public void archiveAllRepositories(String sub) {
 | 
				
			||||||
        List<GHRepository> repositories = this.organization.listRepositories().asList();
 | 
					        List<GHRepository> repositories = this.organization.listRepositories().asList();
 | 
				
			||||||
        for (GHRepository repo : repositories) {
 | 
					        for (GHRepository repo : repositories) {
 | 
				
			||||||
            if (repo.getName().contains(sub)) {
 | 
					            if (repo.getName().contains(sub)) {
 | 
				
			||||||
| 
						 | 
					@ -177,21 +192,62 @@ public class GithubManager {
 | 
				
			||||||
     * Archives a repository so that it can no longer be manipulated.
 | 
					     * Archives a repository so that it can no longer be manipulated.
 | 
				
			||||||
     * TODO: Change to using Github API instead of Apache HttpUtils.
 | 
					     * TODO: Change to using Github API instead of Apache HttpUtils.
 | 
				
			||||||
     * @param repo The repository to archive.
 | 
					     * @param repo The repository to archive.
 | 
				
			||||||
     * @throws IOException If an error occurs with the HTTP request.
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void archiveRepository(GHRepository repo) throws IOException {
 | 
					    private void archiveRepository(GHRepository repo) {
 | 
				
			||||||
        HttpPatch patch = new HttpPatch("https://api.github.com/repos/" + repo.getFullName() + "?access_token=" + this.accessToken);
 | 
					        try {
 | 
				
			||||||
        CloseableHttpClient client = HttpClientBuilder.create().build();
 | 
					            HttpPatch patch = new HttpPatch("https://api.github.com/repos/" + repo.getFullName() + "?access_token=" + this.accessToken);
 | 
				
			||||||
        ObjectMapper mapper = new ObjectMapper();
 | 
					            CloseableHttpClient client = HttpClientBuilder.create().build();
 | 
				
			||||||
        ObjectNode root = mapper.createObjectNode();
 | 
					            ObjectMapper mapper = new ObjectMapper();
 | 
				
			||||||
        root.put("archived", true);
 | 
					            ObjectNode root = mapper.createObjectNode();
 | 
				
			||||||
        String json = mapper.writeValueAsString(root);
 | 
					            root.put("archived", true);
 | 
				
			||||||
        patch.setEntity(new StringEntity(json));
 | 
					            String json = mapper.writeValueAsString(root);
 | 
				
			||||||
        HttpResponse response = client.execute(patch);
 | 
					            patch.setEntity(new StringEntity(json));
 | 
				
			||||||
        if (response.getStatusLine().getStatusCode() != 200) {
 | 
					            HttpResponse response = client.execute(patch);
 | 
				
			||||||
            throw new IOException("Could not archive repository: " + repo.getName() + ". Code: " + response.getStatusLine().getStatusCode());
 | 
					            if (response.getStatusLine().getStatusCode() != 200) {
 | 
				
			||||||
 | 
					                throw new IOException("Could not archive repository: " + repo.getName() + ". Code: " + response.getStatusLine().getStatusCode());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            logger.info("Archived repository: " + repo.getFullName());
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            logger.severe("Could not archive repository: " + repo.getName());
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Invites students in a team to their repository, and the assignments repository.
 | 
				
			||||||
 | 
					     * @param team The team of students to invite as collaborators.
 | 
				
			||||||
 | 
					     * @param repo The repository created for the students.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void inviteStudentsToRepos(StudentTeam team, GHRepository repo) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            logger.finest("Adding students from team: " + team.getId() + " as collaborators.");
 | 
				
			||||||
 | 
					            List<GHUser> users = new ArrayList<>();
 | 
				
			||||||
 | 
					            for (Student student : team.getStudents()) {
 | 
				
			||||||
 | 
					                GHUser user = this.github.getUser(student.getGithubUsername());
 | 
				
			||||||
 | 
					                users.add(user);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            repo.addCollaborators(users);
 | 
				
			||||||
 | 
					            this.assignmentsRepo.addCollaborators(users);
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            logger.severe("Could not add students as collaborators to assignments or their repo.\n" + team);
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Adds a teaching assistant team as admins to a particular student repository.
 | 
				
			||||||
 | 
					     * @param studentRepo The student repository.
 | 
				
			||||||
 | 
					     * @param taTeam The team to give admin rights.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void addTATeamAsAdmin(GHRepository studentRepo, GHTeam taTeam) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            taTeam.add(studentRepo, GHOrganization.Permission.ADMIN);
 | 
				
			||||||
 | 
					            logger.fine("Added team " + taTeam.getName() + " as admin to repository: " + studentRepo.getName());
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            logger.severe("Could not add TA Team: " + taTeam.getName() + " as admins to repository: " + studentRepo.getName());
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        logger.info("Archived repository: " + repo.getFullName());
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -225,7 +281,7 @@ public class GithubManager {
 | 
				
			||||||
            repo.createRef("refs/heads/development", sha1);
 | 
					            repo.createRef("refs/heads/development", sha1);
 | 
				
			||||||
            logger.fine("Created development branch of repository: " + repo.getName());
 | 
					            logger.fine("Created development branch of repository: " + repo.getName());
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            logger.severe("Could not create development branch for repository: " + repo.getName() + '\n' + e.getMessage());
 | 
					            logger.severe("Could not create development branch for repository: " + repo.getName());
 | 
				
			||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -238,7 +294,7 @@ public class GithubManager {
 | 
				
			||||||
     * @param hasWiki Whether the repo has a wiki enabled.
 | 
					     * @param hasWiki Whether the repo has a wiki enabled.
 | 
				
			||||||
     * @param hasIssues Whether the repo has issues enabled.
 | 
					     * @param hasIssues Whether the repo has issues enabled.
 | 
				
			||||||
     * @param isPrivate Whether or not the repository is private.
 | 
					     * @param isPrivate Whether or not the repository is private.
 | 
				
			||||||
     * @return The repository that was created, or
 | 
					     * @return The repository that was created, or null if it could not be created.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private GHRepository createRepository(String name, GHTeam 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 {
 | 
					        try {
 | 
				
			||||||
| 
						 | 
					@ -248,12 +304,12 @@ public class GithubManager {
 | 
				
			||||||
            builder.issues(hasIssues);
 | 
					            builder.issues(hasIssues);
 | 
				
			||||||
            builder.description(description);
 | 
					            builder.description(description);
 | 
				
			||||||
            builder.gitignoreTemplate("Java");
 | 
					            builder.gitignoreTemplate("Java");
 | 
				
			||||||
            builder.private_(isPrivate); // TODO: Change this to true for production
 | 
					            builder.private_(isPrivate);
 | 
				
			||||||
            GHRepository repo = builder.create();
 | 
					            GHRepository repo = builder.create();
 | 
				
			||||||
            logger.fine("Created repository: " + repo.getName());
 | 
					            logger.fine("Created repository: " + repo.getName());
 | 
				
			||||||
            return repo;
 | 
					            return repo;
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            logger.severe("Could not create repository: " + name + '\n' + e.getMessage());
 | 
					            logger.severe("Could not create repository: " + name);
 | 
				
			||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,88 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.error.Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Observable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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 extends Observable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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<StudentTeam> studentTeams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A list of all teaching assistant teams in this organization. These are generated from requests to the Github API
 | 
				
			||||||
 | 
					     * and possibly supplementary information. Each teaching assistant team maintains a list of all student teams for
 | 
				
			||||||
 | 
					     * which it is responsible.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private List<TATeam> taTeams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A queue of errors that accumulates as the program runs. These will be output to the user after execution of
 | 
				
			||||||
 | 
					     * critical sections, so that inevitable errors due to input imperfections are not overlooked.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private List<Error> errors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Constructs a new Organization object with all instance variables initialized to empty values.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public Organization() {
 | 
				
			||||||
 | 
					        this.studentTeams = new ArrayList<>();
 | 
				
			||||||
 | 
					        this.taTeams = new ArrayList<>();
 | 
				
			||||||
 | 
					        this.errors = 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();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Adds an error to the list of accumulated errors.
 | 
				
			||||||
 | 
					     * @param newError The newly generated error to add.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void addError(Error newError) {
 | 
				
			||||||
 | 
					        this.errors.add(newError);
 | 
				
			||||||
 | 
					        this.setChanged();
 | 
				
			||||||
 | 
					        this.notifyObservers();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // GETTERS
 | 
				
			||||||
 | 
					    public List<StudentTeam> getStudentTeams() {
 | 
				
			||||||
 | 
					        return this.studentTeams;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public List<Error> getErrors() {
 | 
				
			||||||
 | 
					        return this.errors;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public List<TATeam> getTaTeams() {
 | 
				
			||||||
 | 
					        return this.taTeams;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // SETTERS
 | 
				
			||||||
 | 
					    public void setStudentTeams(List<StudentTeam> teams) {
 | 
				
			||||||
 | 
					        this.studentTeams = teams;
 | 
				
			||||||
 | 
					        this.setChanged();
 | 
				
			||||||
 | 
					        this.notifyObservers();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setTaTeams(List<TATeam> teams) {
 | 
				
			||||||
 | 
					        this.taTeams = teams;
 | 
				
			||||||
 | 
					        this.setChanged();
 | 
				
			||||||
 | 
					        this.notifyObservers();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,17 @@ public abstract class Person  {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected String githubUsername;
 | 
					    protected String githubUsername;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Constructs a Person from only a github username, which is, in some cases, enough to perform a lot of actions.
 | 
				
			||||||
 | 
					     * @param githubUsername The person's github username.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public Person(String githubUsername) {
 | 
				
			||||||
 | 
					        this.number = -1;
 | 
				
			||||||
 | 
					        this.name = null;
 | 
				
			||||||
 | 
					        this.emailAddress = null;
 | 
				
			||||||
 | 
					        this.githubUsername = githubUsername;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Constructs a Person from all the basic information needed.
 | 
					     * Constructs a Person from all the basic information needed.
 | 
				
			||||||
     * @param number Either an S- or P-Number without the letter prefix.
 | 
					     * @param number Either an S- or P-Number without the letter prefix.
 | 
				
			||||||
| 
						 | 
					@ -72,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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,18 @@ package nl.andrewlalis.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents one student's github information.
 | 
					 * Represents one student's github information.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class Student extends Person {
 | 
					public class Student extends Person {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final Logger logger = Logger.getLogger(Student.class.getName());
 | 
				
			||||||
 | 
					    static {
 | 
				
			||||||
 | 
					        logger.setParent(Logger.getGlobal());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * A list of partners that the student has said that they would like to be partners with.
 | 
					     * A list of partners that the student has said that they would like to be partners with.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
package nl.andrewlalis.model;
 | 
					package nl.andrewlalis.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.kohsuke.github.GHRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -7,6 +9,16 @@ import java.util.Arrays;
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class StudentTeam extends Team{
 | 
					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() {
 | 
					    public StudentTeam() {
 | 
				
			||||||
        super(-1);
 | 
					        super(-1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -24,16 +36,19 @@ public class StudentTeam extends Team{
 | 
				
			||||||
     * A team is valid if and only if:
 | 
					     * A team is valid if and only if:
 | 
				
			||||||
     *      - The student count is equal to the team size.
 | 
					     *      - The student count is equal to the team size.
 | 
				
			||||||
     *      - Each student is unique.
 | 
					     *      - 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.
 | 
					     * @param teamSize The preferred size of teams.
 | 
				
			||||||
     * @return True if the team is valid, and false otherwise.
 | 
					     * @return True if the team is valid, and false otherwise.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public boolean isValid(int teamSize) {
 | 
					    public boolean isValid(int teamSize) {
 | 
				
			||||||
        if (this.memberCount() == teamSize) {
 | 
					        if (this.memberCount() == teamSize) {
 | 
				
			||||||
            for (Student studentA : this.getStudents()) {
 | 
					            for (Student studentA : this.getStudents()) {
 | 
				
			||||||
                for (Student studentB : this.getStudents()) {
 | 
					                // If the student doesn't have an preferred partners, then assume that this is valid.
 | 
				
			||||||
                    if (!studentA.equals(studentB) && !studentA.getPreferredPartners().contains(studentB.getNumber())) {
 | 
					                if (!studentA.getPreferredPartners().isEmpty()) {
 | 
				
			||||||
                        return false;
 | 
					                    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();
 | 
					        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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,63 +1,60 @@
 | 
				
			||||||
package nl.andrewlalis.model;
 | 
					package nl.andrewlalis.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.kohsuke.github.GHOrganization;
 | 
					 | 
				
			||||||
import org.kohsuke.github.GHTeam;
 | 
					import org.kohsuke.github.GHTeam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents a teaching assistant team, which is itself a 'team' in the organization. This class is used for parsing
 | 
					 * Represents a teaching assistant team, which is itself a 'team' in the organization. This class is used for parsing
 | 
				
			||||||
 * json from requests to github to get a list of all teams in the organization.
 | 
					 * json from requests to github to get a list of all teams in the organization.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class TATeam {
 | 
					public class TATeam extends Team {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private List<TeachingAssistant> teachingAssistants;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The team's display name.
 | 
					     * The team's display name.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private String name;
 | 
					    private String name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * The team's unique identifier.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private int id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The Github team associated with this team.
 | 
					     * The Github team associated with this team.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private GHTeam githubTeam;
 | 
					    private GHTeam githubTeam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A list of all student teams for which this TA team is responsible.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private List<StudentTeam> studentTeams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Constructs a team without any teaching assistant members.
 | 
					     * Constructs a team without any teaching assistant members.
 | 
				
			||||||
     * @param name The name of the team.
 | 
					     * @param name The name of the team.
 | 
				
			||||||
     * @param id The unique identifier for this team.
 | 
					     * @param id The unique identifier for this team.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public TATeam(String name, int id) {
 | 
					    public TATeam(String name, int id) {
 | 
				
			||||||
 | 
					        super(id);
 | 
				
			||||||
        this.name = name;
 | 
					        this.name = name;
 | 
				
			||||||
        this.id = id;
 | 
					        this.studentTeams = new ArrayList<>();
 | 
				
			||||||
        this.teachingAssistants = new ArrayList<TeachingAssistant>();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Constructs a team with a list of teaching assistants that are part of it.
 | 
					     * Gets a list of teaching assistants, as a convenience method to avoid having to do an array cast.
 | 
				
			||||||
     * @param teachingAssistants The list of teaching assistants that are part of the team.
 | 
					     * @return An array of all teaching assistant members of this team.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public TATeam(List<TeachingAssistant> teachingAssistants, String name, int id) {
 | 
					    public TeachingAssistant[] getTeachingAssistants() {
 | 
				
			||||||
        this.teachingAssistants = teachingAssistants;
 | 
					        return Arrays.copyOf(this.getMembers(), this.memberCount(), TeachingAssistant[].class);
 | 
				
			||||||
        this.name = name;
 | 
					 | 
				
			||||||
        this.id = id;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets the unique identification for this TA team.
 | 
					     * Adds the given student team to the list of teams that this TA team is responsible for.
 | 
				
			||||||
     * @return An integer representing the id of this team.
 | 
					     * @param team A student team.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public int getId() {
 | 
					    public void addStudentTeam(StudentTeam team) {
 | 
				
			||||||
        return this.id;
 | 
					        this.studentTeams.add(team);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // GETTERS
 | 
				
			||||||
    public String getName() {
 | 
					    public String getName() {
 | 
				
			||||||
        return this.name;
 | 
					        return this.name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -66,6 +63,11 @@ public class TATeam {
 | 
				
			||||||
        return this.githubTeam;
 | 
					        return this.githubTeam;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public List<StudentTeam> getStudentTeams() {
 | 
				
			||||||
 | 
					        return this.studentTeams;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // SETTERS
 | 
				
			||||||
    public void setGithubTeam(GHTeam team) {
 | 
					    public void setGithubTeam(GHTeam team) {
 | 
				
			||||||
        this.githubTeam = team;
 | 
					        this.githubTeam = team;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,18 @@
 | 
				
			||||||
package nl.andrewlalis.model;
 | 
					package nl.andrewlalis.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Represents an administrator in the organization, who manages student teams.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
public class TeachingAssistant extends Person {
 | 
					public class TeachingAssistant extends Person {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Constructs a Teaching Assistant from only a github username.
 | 
				
			||||||
 | 
					     * @param githubUsername The person's github username.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public TeachingAssistant(String githubUsername) {
 | 
				
			||||||
 | 
					        super(githubUsername);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Constructs a Teaching Assistant from all the basic information needed, much like its parent, Person.
 | 
					     * Constructs a Teaching Assistant from all the basic information needed, much like its parent, Person.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,7 +82,7 @@ public class Database {
 | 
				
			||||||
     * @param personType The type of person to store, using a constant defined above.
 | 
					     * @param personType The type of person to store, using a constant defined above.
 | 
				
			||||||
     * @return True if successful, false otherwise.
 | 
					     * @return True if successful, false otherwise.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private boolean storePerson(Person person, int personType) {
 | 
					    public boolean insertPerson(Person person, int personType) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            logger.finest("Storing person: " + person);
 | 
					            logger.finest("Storing person: " + person);
 | 
				
			||||||
            String sql = "INSERT INTO persons (id, name, email_address, github_username, person_type_id) VALUES (?, ?, ?, ?, ?);";
 | 
					            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(3, person.getEmailAddress());
 | 
				
			||||||
            stmt.setString(4, person.getGithubUsername());
 | 
					            stmt.setString(4, person.getGithubUsername());
 | 
				
			||||||
            stmt.setInt(5, personType);
 | 
					            stmt.setInt(5, personType);
 | 
				
			||||||
            stmt.execute();
 | 
					            return stmt.execute();
 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        } catch (SQLException e) {
 | 
					        } catch (SQLException e) {
 | 
				
			||||||
            logger.severe("SQLException while inserting Person: " + person + '\n' + e.getMessage());
 | 
					            logger.severe("SQLException while inserting Person: " + person + '\n' + e.getMessage());
 | 
				
			||||||
            return false;
 | 
					            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<StudentTeam> 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.
 | 
					     * Stores a student in the database.
 | 
				
			||||||
     * @param student The student to store.
 | 
					     * @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.
 | 
					     * @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);
 | 
					        logger.finest("Storing student: " + student);
 | 
				
			||||||
        if (!storePerson(student, PERSON_TYPE_STUDENT)) {
 | 
					        if (!insertPerson(student, PERSON_TYPE_STUDENT)) {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        try {
 | 
					        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);
 | 
					            PreparedStatement stmt = this.connection.prepareStatement(sql);
 | 
				
			||||||
            stmt.setInt(1, student.getNumber());
 | 
					            stmt.setInt(1, student.getNumber());
 | 
				
			||||||
            stmt.setInt(2, teamId);
 | 
					            stmt.setInt(2, student.getPreferredPartners().size() > 0 ? 1 : 0);
 | 
				
			||||||
            stmt.setInt(3, student.getPreferredPartners().size() > 0 ? 1 : 0);
 | 
					            if (!stmt.execute()) {
 | 
				
			||||||
            stmt.execute();
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            // Storing partners.
 | 
					            // Storing partners.
 | 
				
			||||||
            String sqlPartner = "INSERT INTO student_preferred_partners (student_id, partner_id) VALUES (?, ?);";
 | 
					            String sqlPartner = "INSERT INTO student_preferred_partners (student_id, partner_id) VALUES (?, ?);";
 | 
				
			||||||
            PreparedStatement stmtPartner = this.connection.prepareStatement(sqlPartner);
 | 
					            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<StudentTeam> teams) {
 | 
				
			||||||
 | 
					        for (StudentTeam team : teams) {
 | 
				
			||||||
 | 
					            this.insertStudentTeam(team);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Retrieves a list of preferred partners that each student has set.
 | 
					     * Retrieves a list of preferred partners that each student has set.
 | 
				
			||||||
     * @param studentId The student id to search by.
 | 
					     * @param studentId The student id to search by.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,45 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.model.error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.text.DateFormat;
 | 
				
			||||||
 | 
					import java.text.SimpleDateFormat;
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Represents an error that occurs, but does not stop the application while running. Different from an exception in that
 | 
				
			||||||
 | 
					 * errors are meant to be added to a list and processed at a later time, and not hinder the operations in the present.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The time at which this error occurred.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private long timestamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The severity of the error.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private Severity severity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A custom error message generated at the time of the error.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Constructs a new Error with a severity and message.
 | 
				
			||||||
 | 
					     * @param severity The severity of the message.
 | 
				
			||||||
 | 
					     * @param message The custom generated error message for this error.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public Error(Severity severity, String message) {
 | 
				
			||||||
 | 
					        this.timestamp = System.currentTimeMillis();
 | 
				
			||||||
 | 
					        this.severity = severity;
 | 
				
			||||||
 | 
					        this.message = message;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String toString() {
 | 
				
			||||||
 | 
					        DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
 | 
				
			||||||
 | 
					        String dateString = df.format(new Date(this.timestamp));
 | 
				
			||||||
 | 
					        return dateString + ' ' + this.severity.toString() + ": " + this.message;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.model.error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Represents the different levels of severity for errors.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public enum Severity {
 | 
				
			||||||
 | 
					    CRITICAL,       // Anything which happens and could have serious side-effects or massive implications system-wide.
 | 
				
			||||||
 | 
					    HIGH,           // Errors which should be at the top of priority to sort out after a procedure is executed.
 | 
				
			||||||
 | 
					    MEDIUM,         // Medium errors are, as the name implies, of a medium priority.
 | 
				
			||||||
 | 
					    LOW,            // Low severity errors are the smallest errors that should be processed soon to avoid issues.
 | 
				
			||||||
 | 
					    MINOR           // Minor errors are so insignificant that they may not even require user intervention.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import java.text.DateFormat;
 | 
				
			||||||
import java.text.SimpleDateFormat;
 | 
					import java.text.SimpleDateFormat;
 | 
				
			||||||
import java.util.Date;
 | 
					import java.util.Date;
 | 
				
			||||||
import java.util.logging.Handler;
 | 
					import java.util.logging.Handler;
 | 
				
			||||||
 | 
					import java.util.logging.Level;
 | 
				
			||||||
import java.util.logging.LogRecord;
 | 
					import java.util.logging.LogRecord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -26,11 +27,19 @@ public class OutputTextHandler extends Handler {
 | 
				
			||||||
    public void publish(LogRecord logRecord) {
 | 
					    public void publish(LogRecord logRecord) {
 | 
				
			||||||
        DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
 | 
					        DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
 | 
				
			||||||
        String dateString = df.format(new Date(logRecord.getMillis()));
 | 
					        String dateString = df.format(new Date(logRecord.getMillis()));
 | 
				
			||||||
        String sourceLocationString = logRecord.getSourceClassName() + "::" + logRecord.getSourceMethodName();
 | 
					 | 
				
			||||||
        this.outputPane.printStyled(dateString + ' ', "gray_italics");
 | 
					        this.outputPane.printStyled(dateString + ' ', "gray_italics");
 | 
				
			||||||
        this.outputPane.printStyled(logRecord.getLevel().getName() + ": ", "bold");
 | 
					        String style = "default";
 | 
				
			||||||
        this.outputPane.printStyled(sourceLocationString + "\n\t", "bold");
 | 
					        Level level = logRecord.getLevel();
 | 
				
			||||||
        this.outputPane.printStyled(logRecord.getMessage() + '\n', "smaller");
 | 
					        if (level == Level.SEVERE) {
 | 
				
			||||||
 | 
					            style = "error_red";
 | 
				
			||||||
 | 
					        } else if (level == Level.FINE
 | 
				
			||||||
 | 
					        || level == Level.FINER
 | 
				
			||||||
 | 
					        || level == Level.FINEST) {
 | 
				
			||||||
 | 
					            style = "smaller";
 | 
				
			||||||
 | 
					        } else if (level == Level.WARNING) {
 | 
				
			||||||
 | 
					            style = "warning_orange";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.outputPane.printStyled(logRecord.getMessage() + '\n', style);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,8 +63,10 @@ public class CommandExecutor {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void executeCommand(String commandName, String[] args) {
 | 
					    public void executeCommand(String commandName, String[] args) {
 | 
				
			||||||
        if (this.commands.containsKey(commandName)) {
 | 
					        if (this.commands.containsKey(commandName)) {
 | 
				
			||||||
            logger.info(commandName + ' ' + Arrays.toString(args));
 | 
					            logger.info("Command executed: " + commandName + ' ' + Arrays.toString(args));
 | 
				
			||||||
            this.commands.get(commandName).execute(args);
 | 
					            if (!this.commands.get(commandName).execute(args)) {
 | 
				
			||||||
 | 
					                logger.warning("Command did not execute successfully.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            logger.warning(commandName + " is not a valid command.");
 | 
					            logger.warning(commandName + " is not a valid command.");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,6 @@ package nl.andrewlalis.ui.control.command.executables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import nl.andrewlalis.git_api.GithubManager;
 | 
					import nl.andrewlalis.git_api.GithubManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents the action archive all repositories with a certain substring in their name.
 | 
					 * Represents the action archive all repositories with a certain substring in their name.
 | 
				
			||||||
 * It takes the following arguments:
 | 
					 * It takes the following arguments:
 | 
				
			||||||
| 
						 | 
					@ -17,12 +15,7 @@ public class ArchiveRepos extends GithubExecutable {
 | 
				
			||||||
        if (args.length < 1) {
 | 
					        if (args.length < 1) {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        try {
 | 
					        manager.archiveAllRepositories(args[0]);
 | 
				
			||||||
            manager.archiveAllRepositories(args[0]);
 | 
					        return true;
 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        } catch (IOException e) {
 | 
					 | 
				
			||||||
            e.printStackTrace();
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,30 @@
 | 
				
			||||||
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.ui.view.dialogs.DefineTaTeamsDialog;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This executable is slightly different from the others, in that it opens up a user interface to make editing TA teams
 | 
				
			||||||
 | 
					 * possible. Therefore, executing this command opens the 'DefineTaTeams' dialog, within which a user can make changes
 | 
				
			||||||
 | 
					 * to the TA teams in the organization.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
public class DefineTaTeams extends GithubExecutable {
 | 
					public class DefineTaTeams extends GithubExecutable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * An instance of the main application frame; used when constructing the dialog.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private InitializerApp app;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public DefineTaTeams(InitializerApp app) {
 | 
				
			||||||
 | 
					        this.app = app;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected boolean executeWithManager(GithubManager manager, String[] args) {
 | 
					    protected boolean executeWithManager(GithubManager manager, String[] args) {
 | 
				
			||||||
        return false;
 | 
					        DefineTaTeamsDialog dialog = new DefineTaTeamsDialog(this.app, manager);
 | 
				
			||||||
 | 
					        dialog.begin();
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,73 @@
 | 
				
			||||||
 | 
					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.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,
 | 
				
			||||||
 | 
					 * and actually generate the student repositories using the manager.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class DelegateStudentTeams extends GithubExecutable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A reference to the main application frame, used as the parent for the dialog which is shown.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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 (this.app.getOrganization().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<TATeam, Integer> results = dialog.getResult();
 | 
				
			||||||
 | 
					            List<StudentTeam> teams = this.app.getOrganization().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());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                this.app.getOrganization().getTaTeams().add(team);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.control.command.executables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.git_api.GithubManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Deletes all repositories with a given substring.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class DeleteRepos extends GithubExecutable {
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected boolean executeWithManager(GithubManager manager, String[] args) {
 | 
				
			||||||
 | 
					        if (args.length < 1) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        manager.deleteAllRepositories(args[0]);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,12 +0,0 @@
 | 
				
			||||||
package nl.andrewlalis.ui.control.command.executables;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import nl.andrewlalis.git_api.GithubManager;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class GenerateStudentRepos extends GithubExecutable {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    protected boolean executeWithManager(GithubManager manager, String[] args) {
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,9 @@ import nl.andrewlalis.ui.control.command.Executable;
 | 
				
			||||||
 * Requires two arguments:
 | 
					 * Requires two arguments:
 | 
				
			||||||
 * 1. The organization name.
 | 
					 * 1. The organization name.
 | 
				
			||||||
 * 2. The organization's access token.
 | 
					 * 2. The organization's access token.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Any additional arguments are added to a new String[] array which is passed along to child classes, so that they do
 | 
				
			||||||
 | 
					 * not have to filter out the mandatory first two arguments.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class GithubExecutable implements Executable {
 | 
					public abstract class GithubExecutable implements Executable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.control.command.executables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.error.Error;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.control.command.Executable;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This executable lists all errors that have occurred so far in the runtime of the program, and have not been resolved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ListErrors implements Executable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A reference to the current application.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private InitializerApp app;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The logger for outputting debug info.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static final Logger logger = Logger.getLogger(ListErrors.class.getName());
 | 
				
			||||||
 | 
					    static {
 | 
				
			||||||
 | 
					        logger.setParent(Logger.getGlobal());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ListErrors(InitializerApp app) {
 | 
				
			||||||
 | 
					        this.app = app;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean execute(String[] args) {
 | 
				
			||||||
 | 
					        StringBuilder sb = new StringBuilder("Runtime Errors:\n");
 | 
				
			||||||
 | 
					        if (this.app.getOrganization().getErrors().isEmpty()) {
 | 
				
			||||||
 | 
					            sb.append("None");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (Error error : this.app.getOrganization().getErrors()) {
 | 
				
			||||||
 | 
					            sb.append(error).append('\n');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        logger.info(sb.toString());
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,32 +1,31 @@
 | 
				
			||||||
package nl.andrewlalis.ui.control.command.executables;
 | 
					package nl.andrewlalis.ui.control.command.executables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import nl.andrewlalis.model.StudentTeam;
 | 
					import nl.andrewlalis.model.StudentTeam;
 | 
				
			||||||
import nl.andrewlalis.model.database.Database;
 | 
					 | 
				
			||||||
import nl.andrewlalis.ui.control.command.Executable;
 | 
					import nl.andrewlalis.ui.control.command.Executable;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
import nl.andrewlalis.util.FileUtils;
 | 
					import nl.andrewlalis.util.FileUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Execute this class to read students from a supplied filename and teamsize, and store their
 | 
					 * Execute this class to read students from a supplied filename and teamsize, and store their
 | 
				
			||||||
 * information in the database.
 | 
					 * information in the application's organization model.
 | 
				
			||||||
 * Requires the following arguments:
 | 
					 * Requires the following arguments:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * 1. filename
 | 
					 * 1. filename
 | 
				
			||||||
 * 2. teamsize
 | 
					 * 2. teamsize
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class ReadStudentsFileToDB implements Executable {
 | 
					public class ReadStudentsFile implements Executable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The database used to store the students.
 | 
					     * A reference to the current application, which contains the model for storing information.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private Database db;
 | 
					    private InitializerApp app;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ReadStudentsFileToDB(Database db) {
 | 
					    public ReadStudentsFile(InitializerApp app) {
 | 
				
			||||||
        this.db = db;
 | 
					        this.app = app;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean execute(String[] args) {
 | 
					    public boolean execute(String[] args) {
 | 
				
			||||||
        if (args.length < 2) {
 | 
					        if (args.length < 2) {
 | 
				
			||||||
| 
						 | 
					@ -38,6 +37,7 @@ public class ReadStudentsFileToDB implements Executable {
 | 
				
			||||||
        if (teams == null) {
 | 
					        if (teams == null) {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return this.db.storeStudentTeams(teams);
 | 
					        this.app.getOrganization().setStudentTeams(teams);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This executable, when run, sets up all student repositories.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SetupStudentRepos extends GithubExecutable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A reference to the current application.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private InitializerApp app;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SetupStudentRepos(InitializerApp app) {
 | 
				
			||||||
 | 
					        this.app = app;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected boolean executeWithManager(GithubManager manager, String[] args) {
 | 
				
			||||||
 | 
					        if (args.length < 1) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        List<TATeam> taTeams = this.app.getOrganization().getTaTeams();
 | 
				
			||||||
 | 
					        for (TATeam team : taTeams) {
 | 
				
			||||||
 | 
					            for (StudentTeam studentTeam : team.getStudentTeams()) {
 | 
				
			||||||
 | 
					                manager.setupStudentRepo(studentTeam, team, args[0]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,7 @@ public class ArchiveAllListener extends ExecutableListener {
 | 
				
			||||||
    public void actionPerformed(ActionEvent actionEvent) {
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
        String response = JOptionPane.showInputDialog(this.app, "Enter a substring to archive repositories by.", "Enter a substring", JOptionPane.QUESTION_MESSAGE);
 | 
					        String response = JOptionPane.showInputDialog(this.app, "Enter a substring to archive repositories by.", "Enter a substring", JOptionPane.QUESTION_MESSAGE);
 | 
				
			||||||
        if (response != null) {
 | 
					        if (response != null) {
 | 
				
			||||||
            this.executor.executeCommand("archiveall", new String[]{
 | 
					            this.executor.executeCommand("archive_all", new String[]{
 | 
				
			||||||
                    this.app.getOrganizationName(),
 | 
					                    this.app.getOrganizationName(),
 | 
				
			||||||
                    this.app.getAccessToken(),
 | 
					                    this.app.getAccessToken(),
 | 
				
			||||||
                    response
 | 
					                    response
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,9 @@ import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.awt.event.ActionEvent;
 | 
					import java.awt.event.ActionEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Listens for when the user wants to open the 'DefineTaTeams' dialog.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
public class DefineTaTeamsListener extends ExecutableListener {
 | 
					public class DefineTaTeamsListener extends ExecutableListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public DefineTaTeamsListener(CommandExecutor executor, InitializerApp app) {
 | 
					    public DefineTaTeamsListener(CommandExecutor executor, InitializerApp app) {
 | 
				
			||||||
| 
						 | 
					@ -13,6 +16,9 @@ public class DefineTaTeamsListener extends ExecutableListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void actionPerformed(ActionEvent actionEvent) {
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
 | 
					        this.executor.executeCommand("define_ta_teams", new String[]{
 | 
				
			||||||
 | 
					                this.app.getOrganizationName(),
 | 
				
			||||||
 | 
					                this.app.getAccessToken()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.control.listeners;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.control.command.CommandExecutor;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.event.ActionEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Listens for when a user performs an action to open the dialog to delegate student teams amongst the TA teams.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class DelegateStudentTeamsListener extends ExecutableListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public DelegateStudentTeamsListener(CommandExecutor executor, InitializerApp app) {
 | 
				
			||||||
 | 
					        super(executor, app);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
 | 
					        this.executor.executeCommand("delegate_student_teams", new String[]{
 | 
				
			||||||
 | 
					                app.getOrganizationName(),
 | 
				
			||||||
 | 
					                app.getAccessToken()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A listener for when the user wants to delete repositories.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class DeleteReposListener extends ExecutableListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public DeleteReposListener(CommandExecutor executor, InitializerApp app) {
 | 
				
			||||||
 | 
					        super(executor, app);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
 | 
					        String input = JOptionPane.showInputDialog(this.app, "Please enter a string which, if a repository contains it, results in deleting the repository.", "Enter Substing", JOptionPane.QUESTION_MESSAGE);
 | 
				
			||||||
 | 
					        if (input != null) {
 | 
				
			||||||
 | 
					            int decision = JOptionPane.showConfirmDialog(null, "Are you sure you want to delete all repositories that contain \"" + "\" in their name?", "Delete Repositories", JOptionPane.YES_NO_OPTION);
 | 
				
			||||||
 | 
					            if (decision == JOptionPane.YES_OPTION) {
 | 
				
			||||||
 | 
					                this.executor.executeCommand("delete_repos", new String[]{
 | 
				
			||||||
 | 
					                        app.getOrganizationName(),
 | 
				
			||||||
 | 
					                        app.getAccessToken(),
 | 
				
			||||||
 | 
					                        input
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ public class GenerateAssignmentsRepoListener extends ExecutableListener {
 | 
				
			||||||
            String description = JOptionPane.showInputDialog(this.app, "Enter a description for the repository.", "Repository Description", JOptionPane.QUESTION_MESSAGE);
 | 
					            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);
 | 
					            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) {
 | 
					            if (teamName != null) {
 | 
				
			||||||
                this.executor.executeCommand("generateassignments", new String[]{
 | 
					                this.executor.executeCommand("generate_assignments", new String[]{
 | 
				
			||||||
                        this.app.getOrganizationName(),
 | 
					                        this.app.getOrganizationName(),
 | 
				
			||||||
                        this.app.getAccessToken(),
 | 
					                        this.app.getAccessToken(),
 | 
				
			||||||
                        repoName,
 | 
					                        repoName,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,15 @@ import nl.andrewlalis.ui.control.command.CommandExecutor;
 | 
				
			||||||
import nl.andrewlalis.ui.view.InitializerApp;
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.swing.*;
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import javax.swing.filechooser.FileFilter;
 | 
				
			||||||
import java.awt.event.ActionEvent;
 | 
					import java.awt.event.ActionEvent;
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Listens for when the user performs an action to read all students from a file, and output the contents to a database.
 | 
					 * Listens for when the user performs an action to read all students from a file, and output the contents to a database.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Because filename and team size are not provided via arguments when a user clicks on a button, these are obtained via
 | 
				
			||||||
 | 
					 * a JFileChooser and JOptionPane input dialog. If all inputs are valid, then the command is executed.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class ReadStudentsFileListener extends ExecutableListener {
 | 
					public class ReadStudentsFileListener extends ExecutableListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,13 +23,28 @@ public class ReadStudentsFileListener extends ExecutableListener {
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void actionPerformed(ActionEvent actionEvent) {
 | 
					    public void actionPerformed(ActionEvent actionEvent) {
 | 
				
			||||||
        JFileChooser chooser = new JFileChooser();
 | 
					        JFileChooser chooser = new JFileChooser();
 | 
				
			||||||
 | 
					        chooser.setAcceptAllFileFilterUsed(false);
 | 
				
			||||||
 | 
					        chooser.addChoosableFileFilter(new FileFilter() {
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public boolean accept(File file) {
 | 
				
			||||||
 | 
					                if (file.isDirectory()) {
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return file.getName().toLowerCase().endsWith(".csv");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public String getDescription() {
 | 
				
			||||||
 | 
					                return "CSV Files (*.csv)";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
        int fileResponse = chooser.showOpenDialog(this.app);
 | 
					        int fileResponse = chooser.showOpenDialog(this.app);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (fileResponse == JFileChooser.APPROVE_OPTION) {
 | 
					        if (fileResponse == JFileChooser.APPROVE_OPTION) {
 | 
				
			||||||
            String teamSizeString = JOptionPane.showInputDialog(this.app, "Enter the student team size.", "Team Size", JOptionPane.QUESTION_MESSAGE);
 | 
					            String teamSizeString = JOptionPane.showInputDialog(this.app, "Enter the student team size.", "Team Size", JOptionPane.QUESTION_MESSAGE);
 | 
				
			||||||
            if (teamSizeString != null) {
 | 
					            if (teamSizeString != null) {
 | 
				
			||||||
                this.executor.executeCommand("readstudents", new String[]{
 | 
					                this.executor.executeCommand("read_students", new String[]{
 | 
				
			||||||
                        chooser.getSelectedFile().getName(),
 | 
					                        chooser.getSelectedFile().getAbsolutePath(),
 | 
				
			||||||
                        teamSizeString
 | 
					                        teamSizeString
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,13 @@
 | 
				
			||||||
package nl.andrewlalis.ui.view;
 | 
					package nl.andrewlalis.ui.view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.Organization;
 | 
				
			||||||
import nl.andrewlalis.ui.control.OutputTextHandler;
 | 
					import nl.andrewlalis.ui.control.OutputTextHandler;
 | 
				
			||||||
import nl.andrewlalis.ui.control.command.CommandExecutor;
 | 
					import nl.andrewlalis.ui.control.command.CommandExecutor;
 | 
				
			||||||
import nl.andrewlalis.ui.control.command.executables.ArchiveRepos;
 | 
					import nl.andrewlalis.ui.control.listeners.*;
 | 
				
			||||||
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.*;
 | 
					import javax.swing.*;
 | 
				
			||||||
import java.awt.*;
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					import java.awt.event.ActionListener;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.Level;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,15 +34,31 @@ public class InitializerApp extends JFrame {
 | 
				
			||||||
    private JTextField organizationField = new JTextField();
 | 
					    private JTextField organizationField = new JTextField();
 | 
				
			||||||
    private JTextField accessTokenField = new JTextField();
 | 
					    private JTextField accessTokenField = new JTextField();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private JCheckBox privateCheckbox = new JCheckBox("Private");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The executor responsible for performing meaningful actions.
 | 
					     * The executor responsible for performing meaningful actions.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private CommandExecutor executor;
 | 
					    private 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.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public InitializerApp(CommandExecutor executor) {
 | 
					    public InitializerApp(CommandExecutor executor) {
 | 
				
			||||||
        this.executor = executor;
 | 
					        this.executor = executor;
 | 
				
			||||||
 | 
					        this.organization = new Organization();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // UI initialization.
 | 
					        // UI initialization.
 | 
				
			||||||
 | 
					        ImageIcon icon = new ImageIcon(getClass().getResource("/image/icon.png"));
 | 
				
			||||||
 | 
					        this.setIconImage(icon.getImage());
 | 
				
			||||||
        this.initFrame();
 | 
					        this.initFrame();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,7 +66,6 @@ public class InitializerApp extends JFrame {
 | 
				
			||||||
     * Begins showing the application
 | 
					     * Begins showing the application
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void begin() {
 | 
					    public void begin() {
 | 
				
			||||||
        this.pack();
 | 
					 | 
				
			||||||
        this.setVisible(true);
 | 
					        this.setVisible(true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,6 +94,8 @@ public class InitializerApp extends JFrame {
 | 
				
			||||||
        mainPanel.add(this.initGithubManagerPanel(), BorderLayout.EAST);
 | 
					        mainPanel.add(this.initGithubManagerPanel(), BorderLayout.EAST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.setContentPane(mainPanel);
 | 
					        this.setContentPane(mainPanel);
 | 
				
			||||||
 | 
					        this.pack();
 | 
				
			||||||
 | 
					        this.setLocationRelativeTo(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.initLoggingHandler();
 | 
					        this.initLoggingHandler();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -100,6 +115,8 @@ public class InitializerApp extends JFrame {
 | 
				
			||||||
        this.organizationField.setText("InitializerTesting");
 | 
					        this.organizationField.setText("InitializerTesting");
 | 
				
			||||||
        infoInputPanel.add(generateTextFieldPanel("Access Token", this.accessTokenField));
 | 
					        infoInputPanel.add(generateTextFieldPanel("Access Token", this.accessTokenField));
 | 
				
			||||||
        this.accessTokenField.setText("haha get your own");
 | 
					        this.accessTokenField.setText("haha get your own");
 | 
				
			||||||
 | 
					        infoInputPanel.add(this.privateCheckbox);
 | 
				
			||||||
 | 
					        this.privateCheckbox.disable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        githubManagerPanel.add(infoInputPanel, BorderLayout.NORTH);
 | 
					        githubManagerPanel.add(infoInputPanel, BorderLayout.NORTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,22 +124,23 @@ public class InitializerApp extends JFrame {
 | 
				
			||||||
        JPanel commonActionsPanel = new JPanel();
 | 
					        JPanel commonActionsPanel = new JPanel();
 | 
				
			||||||
        commonActionsPanel.setLayout(new BoxLayout(commonActionsPanel, BoxLayout.PAGE_AXIS));
 | 
					        commonActionsPanel.setLayout(new BoxLayout(commonActionsPanel, BoxLayout.PAGE_AXIS));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        JButton archiveAllButton = new JButton("Archive All");
 | 
					        commonActionsPanel.add(this.generateButtonPanel("Archive All", new ArchiveAllListener(this.executor, this)));
 | 
				
			||||||
        archiveAllButton.addActionListener(new ArchiveAllListener(this.executor, this));
 | 
					        commonActionsPanel.add(this.generateButtonPanel("Read Students File", new ReadStudentsFileListener(this.executor, this)));
 | 
				
			||||||
        commonActionsPanel.add(archiveAllButton);
 | 
					        commonActionsPanel.add(this.generateButtonPanel("Delegate Student Teams", new DelegateStudentTeamsListener(this.executor, this)));
 | 
				
			||||||
 | 
					        commonActionsPanel.add(this.generateButtonPanel("Generate Assignments Repo", new GenerateAssignmentsRepoListener(this.executor, this)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        JButton generateStudentTeamsButton = new JButton("Read teams from file");
 | 
					        // TODO: Enable this once the define teams dialog is complete.
 | 
				
			||||||
        generateStudentTeamsButton.addActionListener(new ReadStudentsFileListener(this.executor, this));
 | 
					//        JButton defineTaTeamsButton = new JButton("Define TA Teams");
 | 
				
			||||||
        commonActionsPanel.add(generateStudentTeamsButton);
 | 
					//        defineTaTeamsButton.addActionListener(new DefineTaTeamsListener(this.executor, this));
 | 
				
			||||||
 | 
					//        commonActionsPanel.add(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        JButton generateAssignmentsRepoButton = new JButton("Generate Assignments Repo");
 | 
					        commonActionsPanel.add(this.generateButtonPanel("Delete Repos", new DeleteReposListener(this.executor, this)));
 | 
				
			||||||
        generateAssignmentsRepoButton.addActionListener(new GenerateAssignmentsRepoListener(this.executor, this));
 | 
					 | 
				
			||||||
        commonActionsPanel.add(generateAssignmentsRepoButton);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        JButton defineTaTeamsButton = new JButton("Define TA Teams");
 | 
					        // Extra panel to push buttons to the top.
 | 
				
			||||||
        commonActionsPanel.add(defineTaTeamsButton);
 | 
					        JPanel buttonAlignmentPanel = new JPanel(new BorderLayout());
 | 
				
			||||||
 | 
					        buttonAlignmentPanel.add(commonActionsPanel, BorderLayout.NORTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        githubManagerPanel.add(commonActionsPanel, BorderLayout.CENTER);
 | 
					        githubManagerPanel.add(buttonAlignmentPanel, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return githubManagerPanel;
 | 
					        return githubManagerPanel;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -178,6 +196,20 @@ public class InitializerApp extends JFrame {
 | 
				
			||||||
        return newPanel;
 | 
					        return newPanel;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Generates a button with an attached action listener.
 | 
				
			||||||
 | 
					     * @param buttonText The text to display on the button.
 | 
				
			||||||
 | 
					     * @param listener The listener to attach to the button.
 | 
				
			||||||
 | 
					     * @return A BorderLayout JPanel which contains the button in the CENTER location.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private JPanel generateButtonPanel(String buttonText, ActionListener listener) {
 | 
				
			||||||
 | 
					        JPanel panel = new JPanel(new BorderLayout());
 | 
				
			||||||
 | 
					        JButton button = new JButton(buttonText);
 | 
				
			||||||
 | 
					        button.addActionListener(listener);
 | 
				
			||||||
 | 
					        panel.add(button, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					        return panel;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets the organization name entered in the relevant field.
 | 
					     * Gets the organization name entered in the relevant field.
 | 
				
			||||||
     * @return The organization name the user has entered.
 | 
					     * @return The organization name the user has entered.
 | 
				
			||||||
| 
						 | 
					@ -194,4 +226,20 @@ public class InitializerApp extends JFrame {
 | 
				
			||||||
        return this.accessTokenField.getText().trim();
 | 
					        return this.accessTokenField.getText().trim();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets whether or not the 'private' checkbox is selected.
 | 
				
			||||||
 | 
					     * @return True if the user wishes for repositories to be made private, or false otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isPrivateChecked() {
 | 
				
			||||||
 | 
					        return this.privateCheckbox.isSelected();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Organization getOrganization() {
 | 
				
			||||||
 | 
					        return this.organization;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setAccessToken(String accessToken) {
 | 
				
			||||||
 | 
					        this.accessTokenField.setText(accessToken);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,7 @@
 | 
				
			||||||
package nl.andrewlalis.ui.view;
 | 
					package nl.andrewlalis.ui.view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.swing.*;
 | 
					import javax.swing.*;
 | 
				
			||||||
import javax.swing.text.BadLocationException;
 | 
					import javax.swing.text.*;
 | 
				
			||||||
import javax.swing.text.Style;
 | 
					 | 
				
			||||||
import javax.swing.text.StyleConstants;
 | 
					 | 
				
			||||||
import javax.swing.text.StyledDocument;
 | 
					 | 
				
			||||||
import java.awt.*;
 | 
					import java.awt.*;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
| 
						 | 
					@ -26,6 +23,9 @@ public class OutputTextPane extends JTextPane {
 | 
				
			||||||
        this.initStyles();
 | 
					        this.initStyles();
 | 
				
			||||||
        this.setEditable(false);
 | 
					        this.setEditable(false);
 | 
				
			||||||
        this.setAutoscrolls(true);
 | 
					        this.setAutoscrolls(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DefaultCaret caret = (DefaultCaret) this.getCaret();
 | 
				
			||||||
 | 
					        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void initStyles() {
 | 
					    private void initStyles() {
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,14 @@ public class OutputTextPane extends JTextPane {
 | 
				
			||||||
        Style smaller = this.addStyle("smaller", defaultStyle);
 | 
					        Style smaller = this.addStyle("smaller", defaultStyle);
 | 
				
			||||||
        smaller.addAttribute(StyleConstants.FontSize, 11);
 | 
					        smaller.addAttribute(StyleConstants.FontSize, 11);
 | 
				
			||||||
        this.styles.put("smaller", smaller);
 | 
					        this.styles.put("smaller", smaller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Style errorRed = this.addStyle("error_red", bold);
 | 
				
			||||||
 | 
					        errorRed.addAttribute(StyleConstants.Foreground, new Color(255, 0, 0));
 | 
				
			||||||
 | 
					        this.styles.put("error_red", errorRed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Style warningOrange = this.addStyle("warning_orange", defaultStyle);
 | 
				
			||||||
 | 
					        warningOrange.addAttribute(StyleConstants.Foreground, new Color(255, 127, 0));
 | 
				
			||||||
 | 
					        this.styles.put("warning_orange", warningOrange);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,103 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.dialogs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.git_api.GithubManager;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.list_models.TATeamListCellRenderer;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.list_models.TATeamListModel;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.list_models.TeachingAssistantListCellRenderer;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.list_models.TeachingAssistantsListModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This class represents a pop-up dialog that appears when the user wants to manipulate teams in the organization. With
 | 
				
			||||||
 | 
					 * this dialog, it will be possible to do the following:
 | 
				
			||||||
 | 
					 *  - View all members of the organization.
 | 
				
			||||||
 | 
					 *  - View all teams in the organization.
 | 
				
			||||||
 | 
					 *  - Create new teams from a selection of members.
 | 
				
			||||||
 | 
					 *  - Invite new members to the organization.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class DefineTaTeamsDialog extends JDialog {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final Dimension LIST_SIZE = new Dimension(200, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The manager used to manipulate the organization.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private GithubManager manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public DefineTaTeamsDialog(InitializerApp parentApp, GithubManager manager) {
 | 
				
			||||||
 | 
					        super(parentApp, "Define TA Teams", true);
 | 
				
			||||||
 | 
					        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 | 
				
			||||||
 | 
					        this.manager = manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.initUI();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sets the dialog as visible.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void begin() {
 | 
				
			||||||
 | 
					        this.setVisible(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Constructs all UI components.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void initUI() {
 | 
				
			||||||
 | 
					        JPanel mainPanel = new JPanel(new BorderLayout());
 | 
				
			||||||
 | 
					        mainPanel.add(new JLabel("Hello world", SwingConstants.CENTER), BorderLayout.NORTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mainPanel.add(this.initMembersPanel(), BorderLayout.WEST);
 | 
				
			||||||
 | 
					        mainPanel.add(this.initTeamsPanel(), BorderLayout.EAST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.setContentPane(mainPanel);
 | 
				
			||||||
 | 
					        this.setPreferredSize(new Dimension(600, 800));
 | 
				
			||||||
 | 
					        this.pack();
 | 
				
			||||||
 | 
					        this.setLocationRelativeTo(null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return A JPanel containing the list of teams in the organization.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private JPanel initTeamsPanel() {
 | 
				
			||||||
 | 
					        JPanel teamsPanel = new JPanel(new BorderLayout());
 | 
				
			||||||
 | 
					        teamsPanel.add(new JLabel("Teams", SwingConstants.CENTER), BorderLayout.NORTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ListModel model = new TATeamListModel(this.manager.getTeams());
 | 
				
			||||||
 | 
					        JList teamsList = new JList(model);
 | 
				
			||||||
 | 
					        teamsList.setCellRenderer(new TATeamListCellRenderer());
 | 
				
			||||||
 | 
					        teamsList.setPreferredSize(LIST_SIZE);
 | 
				
			||||||
 | 
					        teamsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        JScrollPane teamsListScrollPane = new JScrollPane(teamsList);
 | 
				
			||||||
 | 
					        teamsListScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
 | 
				
			||||||
 | 
					        teamsListScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
 | 
				
			||||||
 | 
					        teamsPanel.add(teamsListScrollPane, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return teamsPanel;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return A JPanel containing the list of members of the organization.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private JPanel initMembersPanel() {
 | 
				
			||||||
 | 
					        JPanel membersPanel = new JPanel(new BorderLayout());
 | 
				
			||||||
 | 
					        membersPanel.add(new JLabel("Members", SwingConstants.CENTER), BorderLayout.NORTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ListModel model = new TeachingAssistantsListModel(this.manager.getMembers());
 | 
				
			||||||
 | 
					        JList membersList = new JList();
 | 
				
			||||||
 | 
					        membersList.setModel(model);
 | 
				
			||||||
 | 
					        membersList.setCellRenderer(new TeachingAssistantListCellRenderer());
 | 
				
			||||||
 | 
					        membersList.setPreferredSize(LIST_SIZE);
 | 
				
			||||||
 | 
					        membersList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        JScrollPane membersListScrollPane = new JScrollPane(membersList);
 | 
				
			||||||
 | 
					        membersListScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
 | 
				
			||||||
 | 
					        membersListScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
 | 
				
			||||||
 | 
					        membersPanel.add(membersListScrollPane, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return membersPanel;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,174 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.git_api.GithubManager;
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TATeam;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This dialog shows a simple list of all teaching assistant teams, with a JSpinner next to the name, so that a user can
 | 
				
			||||||
 | 
					 * set how many student teams each teaching assistant team would like to manage.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class DelegateStudentTeamsDialog extends JDialog {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The manager used to generate repositories.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private GithubManager manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Indicates how many student teams do not have an assigned team.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private NumberIndicatorField unmatchedStudentsCounter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A list of JSpinner objects linked to specific team members.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private List<TaTeamSpinner> teamSpinners;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A number indicating the total number of student teams.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					        this.teamSpinners = new ArrayList<>();
 | 
				
			||||||
 | 
					        this.totalStudentTeamsCount = parentApp.getOrganization().getStudentTeams().size();
 | 
				
			||||||
 | 
					        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.initUI();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Begins showing the dialog.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void begin() {
 | 
				
			||||||
 | 
					        this.setVisible(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Prepares the user interface components.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void initUI() {
 | 
				
			||||||
 | 
					        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();
 | 
				
			||||||
 | 
					        this.setLocationRelativeTo(null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return A JPanel containing the top-most counter of how many student teams are unassigned, and a small label.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private JPanel generateTopPanel() {
 | 
				
			||||||
 | 
					        JPanel panel = new JPanel(new BorderLayout());
 | 
				
			||||||
 | 
					        panel.add(new JLabel("Unassigned teams: "), BorderLayout.CENTER);
 | 
				
			||||||
 | 
					        this.unmatchedStudentsCounter = new NumberIndicatorField(this.totalStudentTeamsCount);
 | 
				
			||||||
 | 
					        panel.add(this.unmatchedStudentsCounter, BorderLayout.EAST);
 | 
				
			||||||
 | 
					        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 | 
				
			||||||
 | 
					        return panel;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private JPanel generateSpinnersPanel() {
 | 
				
			||||||
 | 
					        JPanel spinnersPanel = new JPanel();
 | 
				
			||||||
 | 
					        spinnersPanel.setLayout(new BoxLayout(spinnersPanel, BoxLayout.PAGE_AXIS));
 | 
				
			||||||
 | 
					        List<TATeam> taTeams = this.manager.getTeams();
 | 
				
			||||||
 | 
					        for (TATeam team : taTeams) {
 | 
				
			||||||
 | 
					            spinnersPanel.add(this.generateTeamSpinnerPanel(team));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        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());
 | 
				
			||||||
 | 
					        teamLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 | 
				
			||||||
 | 
					        panel.add(teamLabel, BorderLayout.WEST);
 | 
				
			||||||
 | 
					        TaTeamSpinner spinner = new TaTeamSpinner(team, this.totalStudentTeamsCount);
 | 
				
			||||||
 | 
					        spinner.addChangeListener(changeEvent -> {
 | 
				
			||||||
 | 
					            JSpinner s = (JSpinner) changeEvent.getSource();
 | 
				
			||||||
 | 
					            int studentTeamsMatched = 0;
 | 
				
			||||||
 | 
					            for (TaTeamSpinner teamSpinner : this.teamSpinners) {
 | 
				
			||||||
 | 
					                studentTeamsMatched += (int)teamSpinner.getValue();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (this.totalStudentTeamsCount - studentTeamsMatched < 0) {
 | 
				
			||||||
 | 
					                s.setValue(s.getPreviousValue());
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.unmatchedStudentsCounter.setValue(this.totalStudentTeamsCount - studentTeamsMatched);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        this.teamSpinners.add(spinner);
 | 
				
			||||||
 | 
					        panel.add(spinner, BorderLayout.EAST);
 | 
				
			||||||
 | 
					        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.
 | 
				
			||||||
 | 
					     * @return A map of TATeams and integer values.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public Map<TATeam, Integer> getResult() {
 | 
				
			||||||
 | 
					        Map<TATeam, Integer> results = new HashMap<>();
 | 
				
			||||||
 | 
					        for (TaTeamSpinner spinner : this.teamSpinners) {
 | 
				
			||||||
 | 
					            results.put(spinner.getTeam(), (int) spinner.getValue());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return results;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A custom JTextField which displays an integer value, and can be set and read more efficiently than if one were to
 | 
				
			||||||
 | 
					 * parse back and forth between strings and integers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class NumberIndicatorField extends JTextField {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The value currently displayed in the text field.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private int value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public NumberIndicatorField(int initialValue) {
 | 
				
			||||||
 | 
					        this.setEditable(false);
 | 
				
			||||||
 | 
					        this.setValue(initialValue);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sets the displayed value to a new integer value.
 | 
				
			||||||
 | 
					     * @param newValue The new value to set.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setValue(int newValue) {
 | 
				
			||||||
 | 
					        this.value = newValue;
 | 
				
			||||||
 | 
					        this.setText(String.valueOf(newValue));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void decrement() {
 | 
				
			||||||
 | 
					        this.setValue(this.value - 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void increment() {
 | 
				
			||||||
 | 
					        this.setValue(this.value + 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getValue() {
 | 
				
			||||||
 | 
					        return this.value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.dialogs.delegateStudentTeams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TATeam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A modified JSpinner which keeps track of a TATeam, and also has a default spinner number model in use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class TaTeamSpinner extends JSpinner {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private TATeam team;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TaTeamSpinner(TATeam team, int max) {
 | 
				
			||||||
 | 
					        super(new SpinnerNumberModel(0, 0, max, 1));
 | 
				
			||||||
 | 
					        ((DefaultEditor) this.getEditor()).getTextField().setEditable(false);
 | 
				
			||||||
 | 
					        this.team = team;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TATeam getTeam() {
 | 
				
			||||||
 | 
					        return this.team;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.list_models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TATeam;
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TeachingAssistant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Determines how list cells are rendered for a list of TATeams. In this case, it shows the team name, and the tooltip
 | 
				
			||||||
 | 
					 * text provides a list of members.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class TATeamListCellRenderer extends DefaultListCellRenderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Component getListCellRendererComponent(JList<?> jList, Object o, int i, boolean b, boolean b1) {
 | 
				
			||||||
 | 
					        super.getListCellRendererComponent(jList, o, i, b, b1);
 | 
				
			||||||
 | 
					        if (o instanceof TATeam) {
 | 
				
			||||||
 | 
					            TATeam team = (TATeam) o;
 | 
				
			||||||
 | 
					            this.setText(team.getName());
 | 
				
			||||||
 | 
					            StringBuilder sb = new StringBuilder();
 | 
				
			||||||
 | 
					            TeachingAssistant[] teachingAssistants = team.getTeachingAssistants();
 | 
				
			||||||
 | 
					            for (int j = 0; j < teachingAssistants.length; j++) {
 | 
				
			||||||
 | 
					                sb.append(teachingAssistants[j].getGithubUsername());
 | 
				
			||||||
 | 
					                if (j < teachingAssistants.length - 1) {
 | 
				
			||||||
 | 
					                    sb.append('\n');
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.setToolTipText(sb.toString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.list_models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TATeam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A list model for displaying TATeams.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class TATeamListModel extends AbstractListModel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A list of teams.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private List<TATeam> teams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TATeamListModel(List<TATeam> taTeams) {
 | 
				
			||||||
 | 
					        this.teams = taTeams;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getSize() {
 | 
				
			||||||
 | 
					        return this.teams.size();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Object getElementAt(int i) {
 | 
				
			||||||
 | 
					        return this.teams.get(i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.list_models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TeachingAssistant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.awt.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Controls what is rendered in a single list cell when displaying a list of TeachingAssistants.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class TeachingAssistantListCellRenderer extends DefaultListCellRenderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Component getListCellRendererComponent(JList<?> jList, Object o, int i, boolean b, boolean b1) {
 | 
				
			||||||
 | 
					        super.getListCellRendererComponent(jList, o, i, b, b1);
 | 
				
			||||||
 | 
					        if (o instanceof TeachingAssistant) {
 | 
				
			||||||
 | 
					            TeachingAssistant ta = (TeachingAssistant) o;
 | 
				
			||||||
 | 
					            this.setText(ta.getGithubUsername());
 | 
				
			||||||
 | 
					            this.setToolTipText(ta.getName());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					package nl.andrewlalis.ui.view.list_models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.TeachingAssistant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.*;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A list model for displaying a list of teaching assistants as members of an organization.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class TeachingAssistantsListModel extends AbstractListModel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The list of teaching assistants which this model uses.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private List<TeachingAssistant> teachingAssistants;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TeachingAssistantsListModel(List<TeachingAssistant> teachingAssistants) {
 | 
				
			||||||
 | 
					        this.teachingAssistants = teachingAssistants;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int getSize() {
 | 
				
			||||||
 | 
					        return this.teachingAssistants.size();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Object getElementAt(int i) {
 | 
				
			||||||
 | 
					        return this.teachingAssistants.get(i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -54,6 +54,7 @@ public class FileUtils {
 | 
				
			||||||
            return studentTeams;
 | 
					            return studentTeams;
 | 
				
			||||||
        } catch (IOException | ArrayIndexOutOfBoundsException e) {
 | 
					        } catch (IOException | ArrayIndexOutOfBoundsException e) {
 | 
				
			||||||
            logger.severe("Unable to generate studentTeams from CSV file, exiting. " + e.getMessage());
 | 
					            logger.severe("Unable to generate studentTeams from CSV file, exiting. " + e.getMessage());
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,24 +11,21 @@ public class Logging {
 | 
				
			||||||
    private static FileHandler outputFile;
 | 
					    private static FileHandler outputFile;
 | 
				
			||||||
    private static SimpleFormatter formatter;
 | 
					    private static SimpleFormatter formatter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void setup(boolean verbose) throws IOException {
 | 
					    public static void setup() {
 | 
				
			||||||
        Logger logger = Logger.getGlobal();
 | 
					        Logger logger = Logger.getGlobal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        outputFile = new FileHandler("log/latest.log");
 | 
					        try {
 | 
				
			||||||
        formatter = new SimpleFormatter();
 | 
					            outputFile = new FileHandler("log/latest.log");
 | 
				
			||||||
 | 
					            formatter = new SimpleFormatter();
 | 
				
			||||||
        outputFile.setFormatter(formatter);
 | 
					            outputFile.setFormatter(formatter);
 | 
				
			||||||
        outputFile.setLevel(Level.FINEST);
 | 
					            outputFile.setLevel(Level.FINEST);
 | 
				
			||||||
 | 
					            logger.addHandler(outputFile);
 | 
				
			||||||
        if (verbose) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            Handler systemOut = new ConsoleHandler();
 | 
					            logger.warning("Unable to save log to output file.");
 | 
				
			||||||
            systemOut.setLevel(Level.ALL);
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					 | 
				
			||||||
            logger.addHandler(systemOut);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        logger.addHandler(outputFile);
 | 
					 | 
				
			||||||
        logger.setLevel(Level.ALL);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        logger.setLevel(Level.ALL);
 | 
				
			||||||
        Logger.getLogger("").setLevel(Level.OFF);
 | 
					        Logger.getLogger("").setLevel(Level.OFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,9 @@ package nl.andrewlalis.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import nl.andrewlalis.model.Student;
 | 
					import nl.andrewlalis.model.Student;
 | 
				
			||||||
import nl.andrewlalis.model.StudentTeam;
 | 
					import nl.andrewlalis.model.StudentTeam;
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.error.Error;
 | 
				
			||||||
 | 
					import nl.andrewlalis.model.error.Severity;
 | 
				
			||||||
 | 
					import nl.andrewlalis.ui.view.InitializerApp;
 | 
				
			||||||
import org.apache.commons.csv.CSVFormat;
 | 
					import org.apache.commons.csv.CSVFormat;
 | 
				
			||||||
import org.apache.commons.csv.CSVRecord;
 | 
					import org.apache.commons.csv.CSVRecord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,8 +153,18 @@ public class TeamGenerator {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Student s = new Student(Integer.parseInt(record.get(3)), record.get(2), record.get(1), record.get(4), preferredIds);
 | 
					            Student s = new Student(Integer.parseInt(record.get(3)), record.get(2), record.get(1), record.get(4), preferredIds);
 | 
				
			||||||
 | 
					            if (studentMap.containsValue(s)) {
 | 
				
			||||||
 | 
					                logger.warning("Duplicate entry found for student: " + s + "\nOverwriting previous value.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            studentMap.put(s.getNumber(), s);
 | 
					            studentMap.put(s.getNumber(), s);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Perform a safety check to ensure all preferred partners are valid students.
 | 
				
			||||||
 | 
					        for (Map.Entry<Integer, Student> entry : studentMap.entrySet()) {
 | 
				
			||||||
 | 
					            // Remove any ids that don't exist in the whole list of students.
 | 
				
			||||||
 | 
					            entry.getValue().getPreferredPartners().removeIf(partnerId -> !studentMap.containsKey(partnerId));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // At this point, all students are valid, and all preferred partners are valid.
 | 
				
			||||||
        logger.fine("Read " + studentMap.size() + " students from records.");
 | 
					        logger.fine("Read " + studentMap.size() + " students from records.");
 | 
				
			||||||
        return studentMap;
 | 
					        return studentMap;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 8.5 KiB  | 
| 
						 | 
					@ -16,12 +16,18 @@ CREATE TABLE IF NOT EXISTS persons (
 | 
				
			||||||
  email_address TEXT NOT NULL,
 | 
					  email_address TEXT NOT NULL,
 | 
				
			||||||
  github_username TEXT NOT NULL UNIQUE,
 | 
					  github_username TEXT NOT NULL UNIQUE,
 | 
				
			||||||
  person_type_id INTEGER NOT NULL,
 | 
					  person_type_id INTEGER NOT NULL,
 | 
				
			||||||
 | 
					  team_id INTEGER NULL,
 | 
				
			||||||
  FOREIGN KEY (person_type_id)
 | 
					  FOREIGN KEY (person_type_id)
 | 
				
			||||||
    REFERENCES person_types(id)
 | 
					    REFERENCES person_types(id)
 | 
				
			||||||
    ON DELETE CASCADE
 | 
					    ON DELETE CASCADE
 | 
				
			||||||
    ON UPDATE CASCADE
 | 
					    ON UPDATE CASCADE,
 | 
				
			||||||
 | 
					  FOREIGN KEY (team_id)
 | 
				
			||||||
 | 
					    REFERENCES teams(id)
 | 
				
			||||||
 | 
					      ON DELETE CASCADE
 | 
				
			||||||
 | 
					      ON UPDATE CASCADE
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Team tables for all types of teams.
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS team_types (
 | 
					CREATE TABLE IF NOT EXISTS team_types (
 | 
				
			||||||
  id INTEGER PRIMARY KEY,
 | 
					  id INTEGER PRIMARY KEY,
 | 
				
			||||||
  name TEXT NOT NULL UNIQUE
 | 
					  name TEXT NOT NULL UNIQUE
 | 
				
			||||||
| 
						 | 
					@ -33,6 +39,22 @@ CREATE TABLE IF NOT EXISTS teams (
 | 
				
			||||||
  FOREIGN KEY (team_type_id)
 | 
					  FOREIGN KEY (team_type_id)
 | 
				
			||||||
    REFERENCES team_types(id)
 | 
					    REFERENCES team_types(id)
 | 
				
			||||||
    ON DELETE CASCADE
 | 
					    ON DELETE CASCADE
 | 
				
			||||||
 | 
					    ON UPDATE CASCADE
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE IF NOT EXISTS team_members (
 | 
				
			||||||
 | 
					  id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
				
			||||||
 | 
					  team_id INTEGER NOT NULL,
 | 
				
			||||||
 | 
					  person_id INTEGER NOT NULL,
 | 
				
			||||||
 | 
					  FOREIGN KEY (team_id)
 | 
				
			||||||
 | 
					    REFERENCES teams(id)
 | 
				
			||||||
 | 
					    ON DELETE CASCADE
 | 
				
			||||||
 | 
					    ON UPDATE CASCADE,
 | 
				
			||||||
 | 
					  FOREIGN KEY (person_id)
 | 
				
			||||||
 | 
					    REFERENCES persons(id)
 | 
				
			||||||
 | 
					    ON DELETE CASCADE
 | 
				
			||||||
 | 
					    ON UPDATE CASCADE,
 | 
				
			||||||
 | 
					  UNIQUE (team_id, person_id)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS teaching_assistant_teams (
 | 
					CREATE TABLE IF NOT EXISTS teaching_assistant_teams (
 | 
				
			||||||
| 
						 | 
					@ -47,7 +69,6 @@ CREATE TABLE IF NOT EXISTS teaching_assistant_teams (
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS student_teams (
 | 
					CREATE TABLE IF NOT EXISTS student_teams (
 | 
				
			||||||
  team_id INTEGER PRIMARY KEY,
 | 
					  team_id INTEGER PRIMARY KEY,
 | 
				
			||||||
  repository_name TEXT,
 | 
					  repository_name TEXT,
 | 
				
			||||||
  group_id INTEGER NOT NULL UNIQUE,
 | 
					 | 
				
			||||||
  teaching_assistant_team_id INTEGER,
 | 
					  teaching_assistant_team_id INTEGER,
 | 
				
			||||||
  FOREIGN KEY (team_id)
 | 
					  FOREIGN KEY (team_id)
 | 
				
			||||||
    REFERENCES teams(id)
 | 
					    REFERENCES teams(id)
 | 
				
			||||||
| 
						 | 
					@ -59,17 +80,13 @@ CREATE TABLE IF NOT EXISTS student_teams (
 | 
				
			||||||
    ON UPDATE CASCADE
 | 
					    ON UPDATE CASCADE
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Student-specific tables.
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS students (
 | 
					CREATE TABLE IF NOT EXISTS students (
 | 
				
			||||||
  person_id INTEGER PRIMARY KEY,
 | 
					  person_id INTEGER PRIMARY KEY,
 | 
				
			||||||
  team_id INTEGER NOT NULL,
 | 
					 | 
				
			||||||
  chose_partner INTEGER NOT NULL,
 | 
					  chose_partner INTEGER NOT NULL,
 | 
				
			||||||
  FOREIGN KEY (person_id)
 | 
					  FOREIGN KEY (person_id)
 | 
				
			||||||
    REFERENCES persons(id)
 | 
					    REFERENCES persons(id)
 | 
				
			||||||
    ON DELETE CASCADE
 | 
					    ON DELETE CASCADE
 | 
				
			||||||
    ON UPDATE CASCADE,
 | 
					 | 
				
			||||||
  FOREIGN KEY (team_id)
 | 
					 | 
				
			||||||
    REFERENCES teams(id)
 | 
					 | 
				
			||||||
    ON DELETE CASCADE
 | 
					 | 
				
			||||||
    ON UPDATE CASCADE
 | 
					    ON UPDATE CASCADE
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,16 +100,12 @@ CREATE TABLE IF NOT EXISTS student_preferred_partners (
 | 
				
			||||||
  UNIQUE (student_id, partner_id)
 | 
					  UNIQUE (student_id, partner_id)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- TeachingAssistant-specific tables.
 | 
				
			||||||
CREATE TABLE IF NOT EXISTS teaching_assistants (
 | 
					CREATE TABLE IF NOT EXISTS teaching_assistants (
 | 
				
			||||||
  person_id INTEGER PRIMARY KEY,
 | 
					  person_id INTEGER PRIMARY KEY,
 | 
				
			||||||
  team_id INTEGER NOT NULL,
 | 
					 | 
				
			||||||
  FOREIGN KEY (person_id)
 | 
					  FOREIGN KEY (person_id)
 | 
				
			||||||
    REFERENCES persons(id)
 | 
					    REFERENCES persons(id)
 | 
				
			||||||
    ON DELETE CASCADE
 | 
					    ON DELETE CASCADE
 | 
				
			||||||
    ON UPDATE CASCADE,
 | 
					 | 
				
			||||||
  FOREIGN KEY (team_id)
 | 
					 | 
				
			||||||
    REFERENCES teams(id)
 | 
					 | 
				
			||||||
    ON DELETE CASCADE
 | 
					 | 
				
			||||||
    ON UPDATE CASCADE
 | 
					    ON UPDATE CASCADE
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue