From 11fb7bcc1dce811783c09597e887f1cb1a7c6dbc Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Mon, 22 Apr 2019 03:04:12 +0200 Subject: [PATCH 1/8] Added ability to edit student information. --- .../controllers/students/StudentEntity.java | 27 ++++++++++ .../model/people/Person.java | 16 ++++++ src/main/resources/static/css/style.css | 4 ++ .../resources/templates/students/entity.html | 4 +- .../templates/students/entity/edit.html | 54 +++++++++++++++++++ 5 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/templates/students/entity/edit.html diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java index db914de..b0768c9 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java @@ -5,7 +5,9 @@ import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentRep import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import java.util.Optional; @@ -24,4 +26,29 @@ public class StudentEntity { optionalStudent.ifPresent(student -> model.addAttribute("student", student)); return "students/entity"; } + + @GetMapping("/students/{id}/edit") + public String getEdit(@PathVariable long id, Model model) { + Optional optionalStudent = this.studentRepository.findById(id); + optionalStudent.ifPresent(student -> model.addAttribute("student", student)); + return "students/entity/edit"; + } + + @PostMapping( + value = "/students/{id}/edit", + consumes = "application/x-www-form-urlencoded" + ) + public String post(@ModelAttribute Student editedStudent, @PathVariable long id) { + Optional optionalStudent = this.studentRepository.findById(id); + optionalStudent.ifPresent(student -> { + student.setFirstName(editedStudent.getFirstName()); + student.setLastName(editedStudent.getLastName()); + student.setEmailAddress(editedStudent.getEmailAddress()); + student.setGithubUsername(editedStudent.getGithubUsername()); + student.setStudentNumber(editedStudent.getStudentNumber()); + this.studentRepository.save(student); + }); + + return "redirect:/students/{id}"; + } } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java index 70245af..c4fea05 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java @@ -94,10 +94,18 @@ public abstract class Person extends BasicEntity { return this.firstName; } + public void setFirstName(String firstName) { + this.firstName = firstName; + } + public String getLastName() { return this.lastName; } + public void setLastName(String lastName) { + this.lastName = lastName; + } + public String getFullName() { return this.getFirstName() + ' ' + this.getLastName(); } @@ -106,10 +114,18 @@ public abstract class Person extends BasicEntity { return this.emailAddress; } + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + public String getGithubUsername() { return this.githubUsername; } + public void setGithubUsername(String githubUsername) { + this.githubUsername = githubUsername; + } + public List getCourses() { return this.courses; } diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css index e1d6b8e..a0338e8 100644 --- a/src/main/resources/static/css/style.css +++ b/src/main/resources/static/css/style.css @@ -39,4 +39,8 @@ body { table, th, td { border: 1px solid black; border-collapse: collapse; +} + +.page_row { + width: 100%; } \ No newline at end of file diff --git a/src/main/resources/templates/students/entity.html b/src/main/resources/templates/students/entity.html index 4576c60..a21baeb 100644 --- a/src/main/resources/templates/students/entity.html +++ b/src/main/resources/templates/students/entity.html @@ -30,7 +30,9 @@ diff --git a/src/main/resources/templates/students/entity/edit.html b/src/main/resources/templates/students/entity/edit.html new file mode 100644 index 0000000..8dd4cff --- /dev/null +++ b/src/main/resources/templates/students/entity/edit.html @@ -0,0 +1,54 @@ + + + + Edit Student + + + +
+

Edit Student:

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ +
+ + + + + \ No newline at end of file From 22fa4ac02cb4cf4706ccc6c4834c0bd6c7342c95 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Mon, 22 Apr 2019 03:15:38 +0200 Subject: [PATCH 2/8] Improved some form styles. --- src/main/resources/static/css/style.css | 6 ++++ .../resources/templates/courses/create.html | 34 ++++++++++++------- .../courses/entity/import_students.html | 16 ++++++--- .../courses/entity/students/invite_all.html | 23 +++++++++---- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css index a0338e8..ee7e261 100644 --- a/src/main/resources/static/css/style.css +++ b/src/main/resources/static/css/style.css @@ -43,4 +43,10 @@ table, th, td { .page_row { width: 100%; + margin-top: 10px; + margin-bottom: 10px; +} + +label { + font-weight: bold; } \ No newline at end of file diff --git a/src/main/resources/templates/courses/create.html b/src/main/resources/templates/courses/create.html index 4751be5..425655a 100644 --- a/src/main/resources/templates/courses/create.html +++ b/src/main/resources/templates/courses/create.html @@ -6,23 +6,33 @@
-

- Create your course here -

+

Create New Course

+
- - +
+ + +
- - +
+ + +
- - +
+ + +
- - +
+ + +
+ +
+ +
-
diff --git a/src/main/resources/templates/courses/entity/import_students.html b/src/main/resources/templates/courses/entity/import_students.html index f825b6b..65f29ef 100644 --- a/src/main/resources/templates/courses/entity/import_students.html +++ b/src/main/resources/templates/courses/entity/import_students.html @@ -6,14 +6,22 @@
+

Import Students from CSV File

+

- Please select a CSV file to import. + Use this form to import student data from a CSV which has been generated by a Google form. As of right now, the column headers are hard-coded, but in the future it will be possible to dynamically import data from any CSV file by custom header format definitions.

- - - +
+ + +
+ +
+ +
+
diff --git a/src/main/resources/templates/courses/entity/students/invite_all.html b/src/main/resources/templates/courses/entity/students/invite_all.html index e0c4bf6..598bfd8 100644 --- a/src/main/resources/templates/courses/entity/students/invite_all.html +++ b/src/main/resources/templates/courses/entity/students/invite_all.html @@ -19,16 +19,25 @@ enctype="application/x-www-form-urlencoded" th:action="@{/courses/{code}/students/invite_all(code=${course.getCode()})}" > - - +
+ + +
- - +
+ + +
- - +
+ + +
- +
+ +
+ From 868c22f8bf16789e1d5bec81f356f5a60d84fc23 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Mon, 22 Apr 2019 05:17:10 +0200 Subject: [PATCH 3/8] Added a shortcut for updating branch protection. --- .../student_teams/UpdateBranchProtection.java | 51 +++++++++++++++++++ .../students/InviteAllToRepository.java | 2 +- .../util/github/GithubManager.java | 33 ++++++++++-- .../courses/entity/student_teams.html | 3 ++ 4 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/UpdateBranchProtection.java diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/UpdateBranchProtection.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/UpdateBranchProtection.java new file mode 100644 index 0000000..41636b0 --- /dev/null +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/UpdateBranchProtection.java @@ -0,0 +1,51 @@ +package nl.andrewlalis.teaching_assistant_assistant.controllers.courses.entity.student_teams; + +import nl.andrewlalis.teaching_assistant_assistant.model.Course; +import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepository; +import nl.andrewlalis.teaching_assistant_assistant.util.github.GithubManager; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import java.io.IOException; +import java.util.Optional; + +/** + * Updates branch protection for all student repositories in a given course. + */ +@Controller +public class UpdateBranchProtection { + + private CourseRepository courseRepository; + + protected UpdateBranchProtection(CourseRepository courseRepository) { + this.courseRepository = courseRepository; + } + + @GetMapping("/courses/{code}/student_teams/branch_protection_update") + public String get(@PathVariable String code) { + Optional optionalCourse = this.courseRepository.findByCode(code); + optionalCourse.ifPresent(course -> { + GithubManager manager; + try { + manager = new GithubManager(course.getApiKey()); + } catch (IOException e) { + e.printStackTrace(); + return; + } + + for (StudentTeam team : course.getStudentTeams()) { + try { + manager.updateBranchProtection(course.getGithubOrganizationName(), team.getGithubRepositoryName(), team.getAssignedTeachingAssistantTeam().getGithubTeamName()); + System.out.println("Updated branch protection for repository " + team.getGithubRepositoryName()); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("Error occurred while trying to enable branch protection for repository " + team.getId()); + } + } + }); + + return "redirect:/courses/{code}/student_teams"; + } +} diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java index 4a791d3..bfa2703 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java @@ -96,7 +96,7 @@ public class InviteAllToRepository { System.out.println("\tInvited " + username); } catch (IOException e) { //e.printStackTrace(); - System.err.println("Could not add " + username + " to repository " + fullRepositoryName); + System.err.println("Could not add " + username + " to repository " + fullRepositoryName + ": " + e.getMessage()); failedNames.add(username); } } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java index 98ab14a..0d84d88 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java @@ -12,12 +12,11 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.kohsuke.github.*; -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; +import java.io.*; import java.net.URL; import java.nio.file.Files; import java.util.Calendar; +import java.util.stream.Collectors; /** * Encapsulates much of the github functionality that is needed. @@ -159,7 +158,7 @@ public class GithubManager { protectionBuilder.includeAdmins(false); protectionBuilder.restrictPushAccess(); protectionBuilder.teamPushAccess(adminTeam); - protectionBuilder.addRequiredChecks("ci/circleci"); + protectionBuilder.addRequiredChecks("ci/circleci: build"); protectionBuilder.enable(); } @@ -188,7 +187,9 @@ public class GithubManager { HttpResponse response = client.execute(put); if (response.getStatusLine().getStatusCode() != 201) { - throw new IOException("Error adding collaborator via url " + url + " : " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()); + String content = new BufferedReader(new InputStreamReader(response.getEntity().getContent())) + .lines().collect(Collectors.joining("\n")); + throw new IOException("Error adding collaborator via url " + url + " : " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase() + "\n" + content); } } catch (JsonProcessingException | UnsupportedEncodingException e) { e.printStackTrace(); @@ -199,4 +200,26 @@ public class GithubManager { team.add(repository, GHOrganization.Permission.ADMIN); } + /** + * Updates branch protection for a given repository. That is, removes old branch protection and reinstates it to + * follow updated circleci conventions. + * @param organizationName The name of the organization. + * @param repositoryName The name of the repository. + * @param teamName The name of the team responsible for this repository. + * @throws IOException If an error occurs with any actions. + */ + public void updateBranchProtection(String organizationName, String repositoryName, String teamName) throws IOException { + GHOrganization organization = this.github.getOrganization(organizationName); + GHRepository repository = organization.getRepository(repositoryName); + GHTeam team = organization.getTeamByName(teamName); + + repository.getBranch("master").disableProtection(); + GHBranchProtectionBuilder builder = repository.getBranch("master").enableProtection(); + builder.includeAdmins(false); + builder.restrictPushAccess(); + builder.teamPushAccess(team); + builder.addRequiredChecks("ci/circleci: build"); + builder.enable(); + } + } diff --git a/src/main/resources/templates/courses/entity/student_teams.html b/src/main/resources/templates/courses/entity/student_teams.html index 12dcbab..1f0c2b3 100644 --- a/src/main/resources/templates/courses/entity/student_teams.html +++ b/src/main/resources/templates/courses/entity/student_teams.html @@ -57,6 +57,9 @@ + From 5670e25a40574cd77089434963ecb98c11cc0fcf Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Mon, 22 Apr 2019 12:30:25 +0200 Subject: [PATCH 4/8] Added headers to students.html --- src/main/resources/templates/courses/entity/students.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/templates/courses/entity/students.html b/src/main/resources/templates/courses/entity/students.html index 6843626..2d56dca 100644 --- a/src/main/resources/templates/courses/entity/students.html +++ b/src/main/resources/templates/courses/entity/students.html @@ -10,6 +10,11 @@

Students in

+ + + + + +
StudentStudent NumberEmail Address
From 64f75ea21d1948f3c86509007c78cefd48497490 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Fri, 26 Apr 2019 20:59:05 +0200 Subject: [PATCH 5/8] Did more than can be explained in a commit message. --- .../controllers/Students.java | 47 +++- .../student_teams/StudentTeamEntity.java | 249 +++++++++++++++++- .../students/InviteAllToRepository.java | 14 +- .../controllers/students/StudentEntity.java | 33 ++- .../model/Course.java | 4 + .../model/people/Person.java | 8 + .../model/people/Student.java | 12 +- .../model/people/teams/StudentTeam.java | 5 + .../model/people/teams/Team.java | 9 + .../util/github/GithubManager.java | 58 +++- .../resources/templates/courses/create.html | 3 - .../courses/entity/student_teams.html | 3 + .../courses/entity/student_teams/create.html | 28 ++ .../courses/entity/student_teams/entity.html | 36 ++- .../student_teams/entity/add_student.html | 35 +++ .../assign_teaching_assistant_team.html | 39 +++ .../resources/templates/fragments/footer.html | 20 +- src/main/resources/templates/students.html | 7 +- .../resources/templates/students/create.html | 60 +++++ 19 files changed, 637 insertions(+), 33 deletions(-) create mode 100644 src/main/resources/templates/courses/entity/student_teams/create.html create mode 100644 src/main/resources/templates/courses/entity/student_teams/entity/add_student.html create mode 100644 src/main/resources/templates/courses/entity/student_teams/entity/assign_teaching_assistant_team.html create mode 100644 src/main/resources/templates/students/create.html diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java index 4086ce3..0406fe3 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java @@ -1,17 +1,29 @@ package nl.andrewlalis.teaching_assistant_assistant.controllers; +import nl.andrewlalis.teaching_assistant_assistant.model.Course; +import nl.andrewlalis.teaching_assistant_assistant.model.people.Student; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepository; import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentRepository; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Optional; @Controller public class Students { - private StudentRepository studentRepository; + private static final String NO_COURSE = "NO_COURSE_SELECTED"; - protected Students(StudentRepository studentRepository) { + private StudentRepository studentRepository; + private CourseRepository courseRepository; + + protected Students(StudentRepository studentRepository, CourseRepository courseRepository) { this.studentRepository = studentRepository; + this.courseRepository = courseRepository; } @GetMapping("/students") @@ -19,4 +31,35 @@ public class Students { model.addAttribute("students", this.studentRepository.findAll()); return "students"; } + + @GetMapping("/students/create") + public String getCreate(Model model) { + model.addAttribute("student", new Student("First Name", "Last Name", "Email Address", "Github Username", 1234567)); + model.addAttribute("courses", this.courseRepository.findAll()); + + return "students/create"; + } + + @PostMapping( + value = "/students/create", + consumes = "application/x-www-form-urlencoded" + ) + public String postCreate( + @ModelAttribute Student newStudent, + @RequestParam(value = "course_code", required = false) String courseCode + ) { + this.studentRepository.save(newStudent); + + if (courseCode != null && !courseCode.equals(NO_COURSE)) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + optionalCourse.ifPresent(course -> { + course.addParticipant(newStudent); + newStudent.assignToCourse(course); + this.courseRepository.save(course); + this.studentRepository.save(newStudent); + }); + } + + return "redirect:/students"; + } } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java index aeae752..4897e2e 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java @@ -1,21 +1,42 @@ package nl.andrewlalis.teaching_assistant_assistant.controllers.courses.entity.student_teams; +import nl.andrewlalis.teaching_assistant_assistant.model.Course; +import nl.andrewlalis.teaching_assistant_assistant.model.people.Student; import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam; +import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.TeachingAssistantTeam; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepository; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentRepository; import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentTeamRepository; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.TeachingAssistantTeamRepository; +import nl.andrewlalis.teaching_assistant_assistant.util.github.GithubManager; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import java.io.IOException; import java.util.Optional; @Controller public class StudentTeamEntity { private StudentTeamRepository studentTeamRepository; + private CourseRepository courseRepository; + private StudentRepository studentRepository; + private TeachingAssistantTeamRepository teachingAssistantTeamRepository; - protected StudentTeamEntity(StudentTeamRepository studentTeamRepository) { + protected StudentTeamEntity( + StudentTeamRepository studentTeamRepository, + CourseRepository courseRepository, + StudentRepository studentRepository, + TeachingAssistantTeamRepository teachingAssistantTeamRepository + ) { this.studentTeamRepository = studentTeamRepository; + this.courseRepository = courseRepository; + this.studentRepository = studentRepository; + this.teachingAssistantTeamRepository = teachingAssistantTeamRepository; } /** @@ -32,4 +53,230 @@ public class StudentTeamEntity { return "courses/entity/student_teams/entity"; } + + @GetMapping("/courses/{courseCode}/student_teams/create") + public String getCreate(@PathVariable String courseCode, Model model) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + optionalCourse.ifPresent(course -> model.addAttribute("course", course)); + + return "courses/entity/student_teams/create"; + } + + @PostMapping("/courses/{courseCode}/student_teams/create") + public String postCreate(@PathVariable String courseCode, Model model) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + optionalCourse.ifPresent(course -> { + StudentTeam team = new StudentTeam(course); + course.addStudentTeam(team); + this.courseRepository.save(course); + }); + + return "redirect:/courses/{courseCode}/student_teams"; + } + + @GetMapping("/courses/{courseCode}/student_teams/{teamId}/add_student") + public String getAddStudent(@PathVariable String courseCode, @PathVariable long teamId, Model model) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); + + if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { + model.addAttribute("course", optionalCourse.get()); + model.addAttribute("student_team", optionalStudentTeam.get()); + model.addAttribute("eligible_students", optionalCourse.get().getStudents()); + } + + return "courses/entity/student_teams/entity/add_student"; + } + + @PostMapping("/courses/{courseCode}/student_teams/{teamId}/add_student") + public String postAddStudent( + @PathVariable String courseCode, + @PathVariable long teamId, + @RequestParam(value = "student_id") long studentId + ) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); + Optional optionalStudent = this.studentRepository.findById(studentId); + + if (optionalCourse.isPresent() && optionalStudentTeam.isPresent() && optionalStudent.isPresent()) { + StudentTeam team = optionalStudentTeam.get(); + Student student = optionalStudent.get(); + + team.addMember(student); + student.assignToTeam(team); + this.studentTeamRepository.save(team); + this.studentRepository.save(student); + } + + return "redirect:/courses/{courseCode}/student_teams"; + } + + @GetMapping("/courses/{courseCode}/student_teams/{teamId}/assign_teaching_assistant_team") + public String getAssignTeachingAssistantTeam( + @PathVariable String courseCode, + @PathVariable long teamId, + Model model + ) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); + + if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { + model.addAttribute("course", optionalCourse.get()); + model.addAttribute("student_team", optionalStudentTeam.get()); + } + + return "courses/entity/student_teams/entity/assign_teaching_assistant_team"; + } + + @PostMapping("/courses/{courseCode}/student_teams/{teamId}/assign_teaching_assistant_team") + public String postAssignTeachingAssistantTeam( + @PathVariable String courseCode, + @PathVariable long teamId, + @RequestParam(value = "teaching_assistant_team_id") long teachingAssistantTeamId + ) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); + Optional optionalTeachingAssistantTeam = this.teachingAssistantTeamRepository.findById(teachingAssistantTeamId); + + if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { + TeachingAssistantTeam teachingAssistantTeam = null; + if (optionalTeachingAssistantTeam.isPresent()) { + teachingAssistantTeam = optionalTeachingAssistantTeam.get(); + } + + StudentTeam studentTeam = optionalStudentTeam.get(); + TeachingAssistantTeam oldTeam = studentTeam.getAssignedTeachingAssistantTeam(); + + // Unset old TA team if it exists. + if (oldTeam != null) { + oldTeam.removeAssignedStudentTeam(studentTeam); + studentTeam.setAssignedTeachingAssistantTeam(null); + this.teachingAssistantTeamRepository.save(oldTeam); + this.studentTeamRepository.save(studentTeam); + } + + // Set new TA team if it exists. + if (teachingAssistantTeam != null) { + studentTeam.setAssignedTeachingAssistantTeam(teachingAssistantTeam); + teachingAssistantTeam.addAssignedStudentTeam(studentTeam); + this.teachingAssistantTeamRepository.save(teachingAssistantTeam); + this.studentTeamRepository.save(studentTeam); + } + } + + return "redirect:/courses/{courseCode}/student_teams"; + } + + @GetMapping("/courses/{courseCode}/student_teams/{teamId}/remove_student/{studentId}") + public String getRemoveStudent( + @PathVariable String courseCode, + @PathVariable long teamId, + @PathVariable long studentId + ) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); + Optional optionalStudent = this.studentRepository.findById(studentId); + + if (optionalCourse.isPresent() && optionalStudentTeam.isPresent() && optionalStudent.isPresent()) { + Student student = optionalStudent.get(); + StudentTeam team = optionalStudentTeam.get(); + Course course = optionalCourse.get(); + + // If the team has a github repository, remove this student as a collaborator. + if (team.getGithubRepositoryName() != null) { + try { + GithubManager manager = new GithubManager(course.getApiKey()); + manager.removeCollaborator(team, student); + System.out.println("Removed " + student.getGithubUsername() + " from " + team.getGithubRepositoryName()); + } catch (IOException e) { + System.err.println("Could not remove student from repository: " + team.getGithubRepositoryName()); + } + } + + team.removeMember(student); + student.removeFromAssignedTeam(team); + + this.studentTeamRepository.save(team); + this.studentRepository.save(student); + } + + return "redirect:/courses/{courseCode}/student_teams/{teamId}"; + } + + @GetMapping("/courses/{courseCode}/student_teams/{teamId}/generate_repository") + public String getGenerateRepository( + @PathVariable String courseCode, + @PathVariable long teamId + ) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); + + if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { + StudentTeam team = optionalStudentTeam.get(); + Course course = optionalCourse.get(); + + if (team.getGithubRepositoryName() == null) { + System.out.println("Generating repository."); + try { + GithubManager manager = new GithubManager(course.getApiKey()); + String name = manager.generateStudentTeamRepository(team); + team.setGithubRepositoryName(name); + this.studentTeamRepository.save(team); + + } catch (IOException e) { + System.err.println("Could not generate repository."); + } + } else { + System.err.println("Repository already exists."); + } + + } else { + System.err.println("Could not find all objects."); + } + + return "redirect:/courses/{courseCode}/student_teams/{teamId}"; + } + + @GetMapping("/courses/{courseCode}/student_teams/{teamId}/remove") + public String remove(@PathVariable String courseCode, @PathVariable long teamId) { + Optional optionalCourse = this.courseRepository.findByCode(courseCode); + Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); + + if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { + StudentTeam team = optionalStudentTeam.get(); + Course course = optionalCourse.get(); + + // Remove the student team at all costs! + if (team.getGithubRepositoryName() != null) { + // First remove all student collaborators. + try { + GithubManager manager = new GithubManager(course.getApiKey()); + manager.deactivateRepository(team); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("Could not deactivate repository."); + } + } + + // Remove all students from this team. + for (Student s : team.getStudents()) { + s.removeFromAssignedTeam(team); + team.removeMember(s); + this.studentRepository.save(s); + } + + // Remove the TA team assignment. + TeachingAssistantTeam teachingAssistantTeam = team.getAssignedTeachingAssistantTeam(); + teachingAssistantTeam.removeAssignedStudentTeam(team); + team.setAssignedTeachingAssistantTeam(null); + this.teachingAssistantTeamRepository.save(teachingAssistantTeam); + + // Remove the repository from the course and delete it. + course.removeStudentTeam(team); + this.studentTeamRepository.delete(team); + this.courseRepository.save(course); + } + + return "redirect:/courses/{courseCode}/student_teams"; + } } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java index bfa2703..1803284 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/students/InviteAllToRepository.java @@ -63,8 +63,6 @@ public class InviteAllToRepository { keys.add(rawKey.trim()); } - String fullRepositoryName = course.getGithubOrganizationName() + '/' + repositoryName; - int inviteCounter = 0; GithubManager manager; try { @@ -80,24 +78,30 @@ public class InviteAllToRepository { if (inviteCounter == 50) { System.out.println("Used up 50 invites on key."); try { + if (keys.isEmpty()) { + System.err.println("No more keys."); + failedNames.addAll(githubUsernames); + break; + } manager = new GithubManager(keys.remove(0)); inviteCounter = 0; } catch (IOException e) { e.printStackTrace(); failedNames.addAll(githubUsernames); - return; + break; } } String username = githubUsernames.remove(0); try { - manager.addCollaborator(fullRepositoryName, username, "pull"); + manager.addCollaborator(course.getGithubOrganizationName(), repositoryName, username, "pull"); inviteCounter++; System.out.println("\tInvited " + username); } catch (IOException e) { //e.printStackTrace(); - System.err.println("Could not add " + username + " to repository " + fullRepositoryName + ": " + e.getMessage()); + System.err.println("Could not add " + username + " to repository " + repositoryName + ": " + e.getMessage()); failedNames.add(username); + inviteCounter = 50; // Try to use a different key if possible. } } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java index b0768c9..9fd8547 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/students/StudentEntity.java @@ -1,7 +1,11 @@ package nl.andrewlalis.teaching_assistant_assistant.controllers.students; +import nl.andrewlalis.teaching_assistant_assistant.model.Course; import nl.andrewlalis.teaching_assistant_assistant.model.people.Student; +import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.Team; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepository; import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentRepository; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.TeamRepository; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -15,9 +19,13 @@ import java.util.Optional; public class StudentEntity { private StudentRepository studentRepository; + private TeamRepository teamRepository; + private CourseRepository courseRepository; - protected StudentEntity(StudentRepository studentRepository) { + protected StudentEntity(StudentRepository studentRepository, TeamRepository teamRepository, CourseRepository courseRepository) { this.studentRepository = studentRepository; + this.teamRepository = teamRepository; + this.courseRepository = courseRepository; } @GetMapping("/students/{id}") @@ -51,4 +59,27 @@ public class StudentEntity { return "redirect:/students/{id}"; } + + @GetMapping("/students/{id}/remove") + public String getRemove(@PathVariable long id) { + Optional optionalStudent = this.studentRepository.findById(id); + optionalStudent.ifPresent(student -> { + + for (Team team : student.getTeams()) { + team.removeMember(student); + student.removeFromAssignedTeam(team); + this.teamRepository.save(team); + } + + for (Course course : student.getCourses()) { + course.removeParticipant(student); + student.removeFromAssignedCourse(course); + this.courseRepository.save(course); + } + + this.studentRepository.delete(student); + }); + + return "redirect:/students"; + } } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java index 8c33111..e22cf53 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java @@ -110,6 +110,10 @@ public class Course extends BasicEntity { this.studentTeams.add(team); } + public void removeStudentTeam(StudentTeam team) { + this.studentTeams.remove(team); + } + public void addTeachingAssistantTeam(TeachingAssistantTeam team) { this.teachingAssistantTeams.add(team); } diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java index c4fea05..5d7446c 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Person.java @@ -80,12 +80,20 @@ public abstract class Person extends BasicEntity { } } + public void removeFromAssignedTeam(Team team) { + this.teams.remove(team); + } + public void assignToCourse(Course course) { if (!this.courses.contains(course)) { this.courses.add(course); } } + public void removeFromAssignedCourse(Course course) { + this.courses.remove(course); + } + /* Getters and Setters */ diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Student.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Student.java index 26963bf..74856c4 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Student.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/Student.java @@ -50,7 +50,17 @@ public class Student extends Person { */ @Override public boolean equals(Object o) { - return super.equals(o) || this.getStudentNumber() == ((Student) o).getStudentNumber(); + if (super.equals(o)) { + return true; + } + + if (!(o instanceof Student)) { + return false; + } + + Student s = (Student) o; + + return this.getStudentNumber() == s.getStudentNumber(); } @Override diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/StudentTeam.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/StudentTeam.java index dad4d47..a201008 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/StudentTeam.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/StudentTeam.java @@ -1,5 +1,6 @@ package nl.andrewlalis.teaching_assistant_assistant.model.people.teams; +import nl.andrewlalis.teaching_assistant_assistant.model.Course; import nl.andrewlalis.teaching_assistant_assistant.model.assignments.grades.AssignmentGrade; import nl.andrewlalis.teaching_assistant_assistant.model.people.Person; import nl.andrewlalis.teaching_assistant_assistant.model.people.Student; @@ -41,6 +42,10 @@ public class StudentTeam extends Team { */ public StudentTeam() {} + public StudentTeam(Course course) { + super(course); + } + public List getStudents() { List people = super.getMembers(); List students = new ArrayList<>(); diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java index 0e81635..c121694 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/people/teams/Team.java @@ -47,6 +47,15 @@ public abstract class Team extends BasicEntity { this.members = new ArrayList<>(); } + /** + * Publicly available constructor in which a course is required. + * @param course The course that this team is in. + */ + public Team(Course course) { + this(); + this.setCourse(course); + } + public void addMember(Person person) { if (!this.containsMember(person)) { this.members.add(person); diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java index 0d84d88..df986b5 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import nl.andrewlalis.teaching_assistant_assistant.model.people.Student; import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam; import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPatch; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; @@ -15,7 +16,9 @@ import org.kohsuke.github.*; import java.io.*; import java.net.URL; import java.nio.file.Files; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import java.util.stream.Collectors; /** @@ -164,7 +167,7 @@ public class GithubManager { private void addStudentsAsCollaborators(GHRepository repository, StudentTeam studentTeam) throws IOException { for (Student student : studentTeam.getStudents()) { - this.addCollaborator(repository.getFullName(), student.getGithubUsername(), "push"); + this.addCollaborator(repository.getOwnerName(), repository.getName(), student.getGithubUsername(), "push"); } } @@ -174,9 +177,9 @@ public class GithubManager { repository.createRef("refs/heads/development", sha1); } - public void addCollaborator(String repositoryName, String githubUsername, String permission) throws IOException { + public void addCollaborator(String organizationName, String repositoryName, String githubUsername, String permission) throws IOException { try { - String url = "https://api.github.com/repos/" + repositoryName + "/collaborators/" + githubUsername + "?access_token=" + this.apiKey; + String url = "https://api.github.com/repos/" + organizationName + '/' + repositoryName + "/collaborators/" + githubUsername + "?access_token=" + this.apiKey; HttpPut put = new HttpPut(url); CloseableHttpClient client = HttpClientBuilder.create().build(); ObjectMapper mapper = new ObjectMapper(); @@ -196,6 +199,36 @@ public class GithubManager { } } + public void removeCollaborator(StudentTeam studentTeam, Student student) throws IOException { + GHOrganization organization = this.github.getOrganization(studentTeam.getCourse().getGithubOrganizationName()); + GHRepository repository = organization.getRepository(studentTeam.getGithubRepositoryName()); + GHUser user = this.github.getUser(student.getGithubUsername()); + + repository.removeCollaborators(user); + } + + /** + * Deactivates a repository by removing all collaborator students, unassigning the repository from the TA team that + * was responsible for it, and archiving it. + * @param studentTeam The student team for which to archive. + * @throws IOException + */ + public void deactivateRepository(StudentTeam studentTeam) throws IOException { + GHOrganization organization = this.github.getOrganization(studentTeam.getCourse().getGithubOrganizationName()); + GHRepository repository = organization.getRepository(studentTeam.getGithubRepositoryName()); + List users = new ArrayList<>(); + for (Student s : studentTeam.getStudents()) { + users.add(this.github.getUser(s.getGithubUsername())); + } + + repository.removeCollaborators(users); + + GHTeam taTeam = organization.getTeamByName(studentTeam.getAssignedTeachingAssistantTeam().getGithubTeamName()); + taTeam.remove(repository); + + this.archiveRepository(repository); + } + private void addRepositoryToTeam(GHTeam team, GHRepository repository) throws IOException { team.add(repository, GHOrganization.Permission.ADMIN); } @@ -222,4 +255,23 @@ public class GithubManager { builder.enable(); } + /** + * Archives a repository so that it can no longer be manipulated. + * TODO: Change to using Github API instead of Apache HttpUtils. + * @param repo The repository to archive. + */ + private void archiveRepository(GHRepository repo) throws IOException { + HttpPatch patch = new HttpPatch("https://api.github.com/repos/" + repo.getFullName() + "?access_token=" + this.apiKey); + CloseableHttpClient client = HttpClientBuilder.create().build(); + ObjectMapper mapper = new ObjectMapper(); + ObjectNode root = mapper.createObjectNode(); + root.put("archived", true); + String json = mapper.writeValueAsString(root); + patch.setEntity(new StringEntity(json)); + HttpResponse response = client.execute(patch); + if (response.getStatusLine().getStatusCode() != 200) { + throw new IOException("Could not archive repository: " + repo.getName() + ". Code: " + response.getStatusLine().getStatusCode()); + } + } + } diff --git a/src/main/resources/templates/courses/create.html b/src/main/resources/templates/courses/create.html index 425655a..35bc337 100644 --- a/src/main/resources/templates/courses/create.html +++ b/src/main/resources/templates/courses/create.html @@ -37,9 +37,6 @@ diff --git a/src/main/resources/templates/courses/entity/student_teams.html b/src/main/resources/templates/courses/entity/student_teams.html index 1f0c2b3..6bb8dc3 100644 --- a/src/main/resources/templates/courses/entity/student_teams.html +++ b/src/main/resources/templates/courses/entity/student_teams.html @@ -66,6 +66,9 @@ + diff --git a/src/main/resources/templates/courses/entity/student_teams/create.html b/src/main/resources/templates/courses/entity/student_teams/create.html new file mode 100644 index 0000000..6aa2f77 --- /dev/null +++ b/src/main/resources/templates/courses/entity/student_teams/create.html @@ -0,0 +1,28 @@ + + + + Create Student Team + + + +
+

Create a New Student Team

+ +

+ Creates a new student team for the course, without any assigned TA team or student members. +

+ +
+ +
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/courses/entity/student_teams/entity.html b/src/main/resources/templates/courses/entity/student_teams/entity.html index dc1af36..fa04e6f 100644 --- a/src/main/resources/templates/courses/entity/student_teams/entity.html +++ b/src/main/resources/templates/courses/entity/student_teams/entity.html @@ -16,7 +16,7 @@ -
  • +
  • Assigned Teaching Assistant Team: + (Remove From This Team)
  • @@ -39,17 +43,37 @@
    + Remove +
    diff --git a/src/main/resources/templates/students/create.html b/src/main/resources/templates/students/create.html new file mode 100644 index 0000000..3d5a5d2 --- /dev/null +++ b/src/main/resources/templates/students/create.html @@ -0,0 +1,60 @@ + + + + Create a Student + + + +
    +

    Create New Student

    + +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +
    + +
    +
    + + + + + \ No newline at end of file From 66530472632e33493aea5adfcc7a4e00100a21c7 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Fri, 10 May 2019 00:49:38 +0200 Subject: [PATCH 6/8] Sort list of eligible students, and some other bullshit. --- .../courses/entity/student_teams/StudentTeamEntity.java | 5 ++++- .../util/github/GithubManager.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java index 4897e2e..0fa0efd 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import java.io.IOException; +import java.util.List; import java.util.Optional; @Controller @@ -80,9 +81,11 @@ public class StudentTeamEntity { Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { + List eligibleStudents = optionalCourse.get().getStudents(); + eligibleStudents.sort((s1, s2) -> s1.getLastName().compareToIgnoreCase(s2.getLastName())); model.addAttribute("course", optionalCourse.get()); model.addAttribute("student_team", optionalStudentTeam.get()); - model.addAttribute("eligible_students", optionalCourse.get().getStudents()); + model.addAttribute("eligible_students", eligibleStudents); } return "courses/entity/student_teams/entity/add_student"; diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java index df986b5..11f2de7 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java @@ -221,7 +221,7 @@ public class GithubManager { users.add(this.github.getUser(s.getGithubUsername())); } - repository.removeCollaborators(users); + //repository.removeCollaborators(users); GHTeam taTeam = organization.getTeamByName(studentTeam.getAssignedTeachingAssistantTeam().getGithubTeamName()); taTeam.remove(repository); From ae2886fe63eade305ad32775b8112c0c388fd8ae Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Fri, 10 May 2019 12:29:01 +0200 Subject: [PATCH 7/8] Added a StudentTeamService and cleaned up controllers which can now make use of it. --- .../controllers/Students.java | 3 + .../student_teams/MergeSingleTeams.java | 65 ++++++ .../student_teams/StudentTeamEntity.java | 147 ++++-------- .../services/StudentTeamService.java | 213 ++++++++++++++++++ .../util/github/GithubManager.java | 34 ++- .../courses/entity/student_teams.html | 3 + 6 files changed, 346 insertions(+), 119 deletions(-) create mode 100644 src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java create mode 100644 src/main/java/nl/andrewlalis/teaching_assistant_assistant/services/StudentTeamService.java diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java index 0406fe3..3b4a14b 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/Students.java @@ -13,6 +13,9 @@ import org.springframework.web.bind.annotation.RequestParam; import java.util.Optional; +/** + * Controller for operations dealing with the global collection of students, not particular to one course. + */ @Controller public class Students { diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java new file mode 100644 index 0000000..e7980e4 --- /dev/null +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java @@ -0,0 +1,65 @@ +package nl.andrewlalis.teaching_assistant_assistant.controllers.courses.entity.student_teams; + +import nl.andrewlalis.teaching_assistant_assistant.model.Course; +import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepository; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentTeamRepository; +import nl.andrewlalis.teaching_assistant_assistant.services.StudentTeamService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Controller +public class MergeSingleTeams { + + private Logger logger = LogManager.getLogger(MergeSingleTeams.class); + + private CourseRepository courseRepository; + private StudentTeamRepository studentTeamRepository; + + private StudentTeamService studentTeamService; + + protected MergeSingleTeams(CourseRepository courseRepository, StudentTeamRepository studentTeamRepository, StudentTeamService studentTeamService) { + this.courseRepository = courseRepository; + this.studentTeamRepository = studentTeamRepository; + this.studentTeamService = studentTeamService; + } + + @GetMapping("/courses/{code}/student_teams/merge_single_teams") + public String get(@PathVariable String code) { + Optional optionalCourse = this.courseRepository.findByCode(code); + if (optionalCourse.isPresent()) { + Course course = optionalCourse.get(); + List singleTeams = this.getAllSingleTeams(course); + singleTeams.forEach(team -> logger.info("Team " + team.getId() + " is a single team.")); + +// while (singleTeams.size() > 1) { +// StudentTeam single1 = singleTeams.remove(0); +// StudentTeam single2 = singleTeams.remove(0); +// +// // Todo: use a service here and when removing a team in another location to avoid duplication. +// StudentTeam newTeam = this.studentTeamService.createNewStudentTeam(course); +// } + } + + return "redirect:/courses/{code}/student_teams"; + } + + private List getAllSingleTeams(Course course) { + List allTeams = course.getStudentTeams(); + List singleTeams = new ArrayList<>(); + for (StudentTeam team : allTeams) { + if (team.getMembers().size() == 1) { + singleTeams.add(team); + } + } + return singleTeams; + } + +} diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java index 0fa0efd..18cf28d 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/StudentTeamEntity.java @@ -8,7 +8,7 @@ import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepo import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentRepository; import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentTeamRepository; import nl.andrewlalis.teaching_assistant_assistant.model.repositories.TeachingAssistantTeamRepository; -import nl.andrewlalis.teaching_assistant_assistant.util.github.GithubManager; +import nl.andrewlalis.teaching_assistant_assistant.services.StudentTeamService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -16,7 +16,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; -import java.io.IOException; import java.util.List; import java.util.Optional; @@ -27,17 +26,20 @@ public class StudentTeamEntity { private CourseRepository courseRepository; private StudentRepository studentRepository; private TeachingAssistantTeamRepository teachingAssistantTeamRepository; + private StudentTeamService studentTeamService; protected StudentTeamEntity( StudentTeamRepository studentTeamRepository, CourseRepository courseRepository, StudentRepository studentRepository, - TeachingAssistantTeamRepository teachingAssistantTeamRepository + TeachingAssistantTeamRepository teachingAssistantTeamRepository, + StudentTeamService studentTeamService ) { this.studentTeamRepository = studentTeamRepository; this.courseRepository = courseRepository; this.studentRepository = studentRepository; this.teachingAssistantTeamRepository = teachingAssistantTeamRepository; + this.studentTeamService = studentTeamService; } /** @@ -63,14 +65,16 @@ public class StudentTeamEntity { return "courses/entity/student_teams/create"; } + /** + * Mapping for creating a new student team. + * @param courseCode The course code. + * @param model The view model. + * @return A redirect to the list of student teams. + */ @PostMapping("/courses/{courseCode}/student_teams/create") public String postCreate(@PathVariable String courseCode, Model model) { Optional optionalCourse = this.courseRepository.findByCode(courseCode); - optionalCourse.ifPresent(course -> { - StudentTeam team = new StudentTeam(course); - course.addStudentTeam(team); - this.courseRepository.save(course); - }); + optionalCourse.ifPresent(course -> this.studentTeamService.createNewStudentTeam(course)); return "redirect:/courses/{courseCode}/student_teams"; } @@ -91,6 +95,13 @@ public class StudentTeamEntity { return "courses/entity/student_teams/entity/add_student"; } + /** + * Mapping for adding a new student to this team. + * @param courseCode The course code. + * @param teamId The id of the team to add the student to. + * @param studentId The id of an existing student to add to this team. + * @return A redirect to the list of student teams. + */ @PostMapping("/courses/{courseCode}/student_teams/{teamId}/add_student") public String postAddStudent( @PathVariable String courseCode, @@ -102,16 +113,10 @@ public class StudentTeamEntity { Optional optionalStudent = this.studentRepository.findById(studentId); if (optionalCourse.isPresent() && optionalStudentTeam.isPresent() && optionalStudent.isPresent()) { - StudentTeam team = optionalStudentTeam.get(); - Student student = optionalStudent.get(); - - team.addMember(student); - student.assignToTeam(team); - this.studentTeamRepository.save(team); - this.studentRepository.save(student); + this.studentTeamService.addStudent(optionalStudentTeam.get(), optionalStudent.get()); } - return "redirect:/courses/{courseCode}/student_teams"; + return "redirect:/courses/{courseCode}/student_teams/{teamId}"; } @GetMapping("/courses/{courseCode}/student_teams/{teamId}/assign_teaching_assistant_team") @@ -131,6 +136,13 @@ public class StudentTeamEntity { return "courses/entity/student_teams/entity/assign_teaching_assistant_team"; } + /** + * Endpoint for assigning a teaching assistant team to this student team. + * @param courseCode The course code. + * @param teamId The id of the student team. + * @param teachingAssistantTeamId The id of the teaching assistant team. + * @return A redirect to the team responsible. + */ @PostMapping("/courses/{courseCode}/student_teams/{teamId}/assign_teaching_assistant_team") public String postAssignTeachingAssistantTeam( @PathVariable String courseCode, @@ -147,29 +159,19 @@ public class StudentTeamEntity { teachingAssistantTeam = optionalTeachingAssistantTeam.get(); } - StudentTeam studentTeam = optionalStudentTeam.get(); - TeachingAssistantTeam oldTeam = studentTeam.getAssignedTeachingAssistantTeam(); - - // Unset old TA team if it exists. - if (oldTeam != null) { - oldTeam.removeAssignedStudentTeam(studentTeam); - studentTeam.setAssignedTeachingAssistantTeam(null); - this.teachingAssistantTeamRepository.save(oldTeam); - this.studentTeamRepository.save(studentTeam); - } - - // Set new TA team if it exists. - if (teachingAssistantTeam != null) { - studentTeam.setAssignedTeachingAssistantTeam(teachingAssistantTeam); - teachingAssistantTeam.addAssignedStudentTeam(studentTeam); - this.teachingAssistantTeamRepository.save(teachingAssistantTeam); - this.studentTeamRepository.save(studentTeam); - } + this.studentTeamService.assignTeachingAssistantTeam(optionalStudentTeam.get(), teachingAssistantTeam); } - return "redirect:/courses/{courseCode}/student_teams"; + return "redirect:/courses/{courseCode}/student_teams/{teamId}"; } + /** + * Endpoint for removing a student from the student team. + * @param courseCode The code for the course. + * @param teamId The id of the team. + * @param studentId The student's id. + * @return A redirect to the team after the student is removed. + */ @GetMapping("/courses/{courseCode}/student_teams/{teamId}/remove_student/{studentId}") public String getRemoveStudent( @PathVariable String courseCode, @@ -181,26 +183,7 @@ public class StudentTeamEntity { Optional optionalStudent = this.studentRepository.findById(studentId); if (optionalCourse.isPresent() && optionalStudentTeam.isPresent() && optionalStudent.isPresent()) { - Student student = optionalStudent.get(); - StudentTeam team = optionalStudentTeam.get(); - Course course = optionalCourse.get(); - - // If the team has a github repository, remove this student as a collaborator. - if (team.getGithubRepositoryName() != null) { - try { - GithubManager manager = new GithubManager(course.getApiKey()); - manager.removeCollaborator(team, student); - System.out.println("Removed " + student.getGithubUsername() + " from " + team.getGithubRepositoryName()); - } catch (IOException e) { - System.err.println("Could not remove student from repository: " + team.getGithubRepositoryName()); - } - } - - team.removeMember(student); - student.removeFromAssignedTeam(team); - - this.studentTeamRepository.save(team); - this.studentRepository.save(student); + this.studentTeamService.removeStudent(optionalStudentTeam.get(), optionalStudent.get()); } return "redirect:/courses/{courseCode}/student_teams/{teamId}"; @@ -215,26 +198,7 @@ public class StudentTeamEntity { Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { - StudentTeam team = optionalStudentTeam.get(); - Course course = optionalCourse.get(); - - if (team.getGithubRepositoryName() == null) { - System.out.println("Generating repository."); - try { - GithubManager manager = new GithubManager(course.getApiKey()); - String name = manager.generateStudentTeamRepository(team); - team.setGithubRepositoryName(name); - this.studentTeamRepository.save(team); - - } catch (IOException e) { - System.err.println("Could not generate repository."); - } - } else { - System.err.println("Repository already exists."); - } - - } else { - System.err.println("Could not find all objects."); + this.studentTeamService.generateRepository(optionalStudentTeam.get()); } return "redirect:/courses/{courseCode}/student_teams/{teamId}"; @@ -246,38 +210,7 @@ public class StudentTeamEntity { Optional optionalStudentTeam = this.studentTeamRepository.findById(teamId); if (optionalCourse.isPresent() && optionalStudentTeam.isPresent()) { - StudentTeam team = optionalStudentTeam.get(); - Course course = optionalCourse.get(); - - // Remove the student team at all costs! - if (team.getGithubRepositoryName() != null) { - // First remove all student collaborators. - try { - GithubManager manager = new GithubManager(course.getApiKey()); - manager.deactivateRepository(team); - } catch (IOException e) { - e.printStackTrace(); - System.err.println("Could not deactivate repository."); - } - } - - // Remove all students from this team. - for (Student s : team.getStudents()) { - s.removeFromAssignedTeam(team); - team.removeMember(s); - this.studentRepository.save(s); - } - - // Remove the TA team assignment. - TeachingAssistantTeam teachingAssistantTeam = team.getAssignedTeachingAssistantTeam(); - teachingAssistantTeam.removeAssignedStudentTeam(team); - team.setAssignedTeachingAssistantTeam(null); - this.teachingAssistantTeamRepository.save(teachingAssistantTeam); - - // Remove the repository from the course and delete it. - course.removeStudentTeam(team); - this.studentTeamRepository.delete(team); - this.courseRepository.save(course); + this.studentTeamService.removeTeam(optionalStudentTeam.get()); } return "redirect:/courses/{courseCode}/student_teams"; diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/services/StudentTeamService.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/services/StudentTeamService.java new file mode 100644 index 0000000..24f29a2 --- /dev/null +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/services/StudentTeamService.java @@ -0,0 +1,213 @@ +package nl.andrewlalis.teaching_assistant_assistant.services; + +import nl.andrewlalis.teaching_assistant_assistant.model.Course; +import nl.andrewlalis.teaching_assistant_assistant.model.people.Student; +import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam; +import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.TeachingAssistantTeam; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepository; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentRepository; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentTeamRepository; +import nl.andrewlalis.teaching_assistant_assistant.model.repositories.TeachingAssistantTeamRepository; +import nl.andrewlalis.teaching_assistant_assistant.util.github.GithubManager; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.List; + +/** + * This service is used to control the manipulation, creation and deletion of student teams. + */ +@Service +public class StudentTeamService { + + private Logger logger = LogManager.getLogger(StudentTeamService.class); + + private StudentTeamRepository studentTeamRepository; + private StudentRepository studentRepository; + private CourseRepository courseRepository; + private TeachingAssistantTeamRepository teachingAssistantTeamRepository; + + public StudentTeamService( + StudentTeamRepository studentTeamRepository, + StudentRepository studentRepository, + CourseRepository courseRepository, + TeachingAssistantTeamRepository teachingAssistantTeamRepository + ) { + this.studentTeamRepository = studentTeamRepository; + this.studentRepository = studentRepository; + this.courseRepository = courseRepository; + this.teachingAssistantTeamRepository = teachingAssistantTeamRepository; + } + + /** + * Creates a new empty student team. + * @param course The course that the student team is in. + * @return The newly created student team. + */ + public StudentTeam createNewStudentTeam(Course course) { + StudentTeam newTeam = new StudentTeam(course); + course.addStudentTeam(newTeam); + this.courseRepository.save(course); + logger.info("Created new team: " + newTeam.getId()); + + return newTeam; + } + + /** + * Creates a new student team, and populates it with some students and automatically assigns a teaching assistant + * team. + * @param course The course to which the team will belong. + * @param students The list of students to add to the team. + * @param teachingAssistantTeam The teaching assistant team responsible for this new team. + * @return The newly created student team. + */ + public StudentTeam createNewStudentTeam(Course course, List students, TeachingAssistantTeam teachingAssistantTeam) { + StudentTeam emptyTeam = this.createNewStudentTeam(course); + + emptyTeam.setAssignedTeachingAssistantTeam(teachingAssistantTeam); + teachingAssistantTeam.addAssignedStudentTeam(emptyTeam); + this.teachingAssistantTeamRepository.save(teachingAssistantTeam); + + for (Student student : students) { + this.addStudent(emptyTeam, student); + } + + return emptyTeam; + } + + /** + * Adds a new student to this team. + * @param team The team to add the student to. + * @param student The student to add. + */ + public void addStudent(StudentTeam team, Student student) { + team.addMember(student); + student.assignToTeam(team); + this.studentTeamRepository.save(team); + this.studentRepository.save(student); + } + + /** + * Removes a single student from a team, and if that team has a github repository, tries to remove the student from + * that as well. + * @param studentTeam The student team to remove the student from. + * @param student The student to remove. + */ + public void removeStudent(StudentTeam studentTeam, Student student) { + studentTeam.removeMember(student); + student.removeFromAssignedTeam(studentTeam); + + this.studentTeamRepository.save(studentTeam); + this.studentRepository.save(student); + + if (studentTeam.getGithubRepositoryName() != null) { + try { + logger.debug("Removing " + student.getGithubUsername() + " from repository " + studentTeam.getGithubRepositoryName()); + GithubManager manager = new GithubManager(studentTeam.getCourse().getApiKey()); + manager.removeCollaborator(studentTeam, student); + } catch (IOException e) { + logger.catching(e); + logger.error("Could not remove student from repository: " + studentTeam.getGithubRepositoryName()); + } + } + + logger.info("Removed student " + student.getFullName() + " from team " + studentTeam.getId()); + } + + /** + * Assigns a new teaching assistant team to a student team. + * @param studentTeam The student team. + * @param teachingAssistantTeam The teaching assistant team to assign the student team to. + * This may be null. + */ + public void assignTeachingAssistantTeam(StudentTeam studentTeam, TeachingAssistantTeam teachingAssistantTeam) { + TeachingAssistantTeam oldTeachingAssistantTeam = studentTeam.getAssignedTeachingAssistantTeam(); + + if (oldTeachingAssistantTeam != null) { + oldTeachingAssistantTeam.removeAssignedStudentTeam(studentTeam); + studentTeam.setAssignedTeachingAssistantTeam(null); + this.teachingAssistantTeamRepository.save(oldTeachingAssistantTeam); + } + + if (teachingAssistantTeam != null) { + studentTeam.setAssignedTeachingAssistantTeam(teachingAssistantTeam); + teachingAssistantTeam.addAssignedStudentTeam(studentTeam); + this.teachingAssistantTeamRepository.save(teachingAssistantTeam); + } + + this.studentTeamRepository.save(studentTeam); + + logger.info("Assigned teaching assistant team " + teachingAssistantTeam + " to student team " + studentTeam.getId()); + } + + /** + * Uses a {@link GithubManager} to generate a repository for this student team. + * @param team The team to generate a repository for. + */ + public void generateRepository(StudentTeam team) { + if (team.getGithubRepositoryName() == null) { + try { + GithubManager manager = new GithubManager(team.getCourse().getApiKey()); + String name = manager.generateStudentTeamRepository(team); + team.setGithubRepositoryName(name); + this.studentTeamRepository.save(team); + } catch (IOException e) { + logger.error("Could not generate repository."); + } + } else { + logger.warn("Repository " + team.getGithubRepositoryName() + " already exists."); + } + } + + /** + * Removes the given team, archives the repository if one exists. + * @param team The team to remove. + */ + public void removeTeam(StudentTeam team) { + Course course = team.getCourse(); + + // Remove the student team at all costs! + if (team.getGithubRepositoryName() != null) { + // First remove all student collaborators. + try { + GithubManager manager = new GithubManager(course.getApiKey()); + manager.deactivateRepository(team); + } catch (IOException e) { + e.printStackTrace(); + logger.error("Could not deactivate repository."); + } + } + + // Remove all students from this team. + for (Student s : team.getStudents()) { + s.removeFromAssignedTeam(team); + team.removeMember(s); + this.studentRepository.save(s); + } + + // Remove the TA team assignment. + TeachingAssistantTeam teachingAssistantTeam = team.getAssignedTeachingAssistantTeam(); + teachingAssistantTeam.removeAssignedStudentTeam(team); + team.setAssignedTeachingAssistantTeam(null); + this.teachingAssistantTeamRepository.save(teachingAssistantTeam); + + // Remove the repository from the course and delete it. + course.removeStudentTeam(team); + this.studentTeamRepository.delete(team); + this.courseRepository.save(course); + + logger.info("Removed team " + team.getId()); + } + + /** + * Merges all teams consisting of a single student so that new teams are generated. + * + * TODO: Make this team size independent. + */ + public void mergeSingleTeams() { + + } + +} diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java index 11f2de7..9b7334e 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/util/github/GithubManager.java @@ -11,6 +11,8 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.kohsuke.github.*; import java.io.*; @@ -26,6 +28,8 @@ import java.util.stream.Collectors; */ public class GithubManager { + Logger logger = LogManager.getLogger(GithubManager.class); + private GitHub github; private String apiKey; @@ -55,13 +59,14 @@ public class GithubManager { * @return The name of the created repository. */ public String generateStudentTeamRepository(StudentTeam team) { - GHOrganization organization; + logger.info("Generating repository for student team " + team.getId()); + GHOrganization organization; try { organization = this.github.getOrganization(team.getCourse().getGithubOrganizationName()); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not get Github organization with name: " + team.getCourse().getGithubOrganizationName()); + logger.error("Could not get Github organization with name: " + team.getCourse().getGithubOrganizationName()); return null; } @@ -71,12 +76,11 @@ public class GithubManager { // Get the TA team which manages this repository. GHTeam teachingAssistantGithubTeam; - try { teachingAssistantGithubTeam = organization.getTeamByName(team.getAssignedTeachingAssistantTeam().getGithubTeamName()); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not get team by name: " + team.getAssignedTeachingAssistantTeam().getGithubTeamName()); + logger.error("Could not get team by name: " + team.getAssignedTeachingAssistantTeam().getGithubTeamName()); return null; } @@ -89,50 +93,56 @@ public class GithubManager { repositoryBuilder.autoInit(false); GHRepository repository; try { - repository = repositoryBuilder.create(); + logger.debug("Creating empty repository " + repositoryName); + repository = repositoryBuilder.create(); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not create repository: " + repositoryName); + logger.error("Could not create repository: " + repositoryName); return null; } try { + logger.debug("Assigning teaching assistant team " + teachingAssistantGithubTeam.getName() + " to repository."); this.addRepositoryToTeam(teachingAssistantGithubTeam, repository); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not add repository " + repositoryName + " to team " + teachingAssistantGithubTeam.getName()); + logger.error("Could not add repository " + repositoryName + " to team " + teachingAssistantGithubTeam.getName()); return null; } try { + logger.debug("Adding starting file to the repository."); this.addStarterFile(repository, "program_resources/getting_started.md", "getting_started.md"); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not add the starter file to the repository: " + repositoryName); + logger.error("Could not add the starter file to the repository: " + repositoryName); return null; } try { + logger.debug("Creating development branch."); this.createDevelopmentBranch(repository); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not create development branch for repository: " + repositoryName); + logger.error("Could not create development branch for repository: " + repositoryName); return null; } try { + logger.debug("Adding protections to the master branch."); this.protectMasterBranch(repository, teachingAssistantGithubTeam); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not add protections to the master branch of " + repositoryName); + logger.error("Could not add protections to the master branch of " + repositoryName); return null; } try { + logger.debug("Adding students as collaborators."); this.addStudentsAsCollaborators(repository, team); } catch (IOException e) { e.printStackTrace(); - System.err.println("Could not add students as collaborators to " + repositoryName); + logger.error("Could not add students as collaborators to " + repositoryName); return null; } @@ -211,7 +221,7 @@ public class GithubManager { * Deactivates a repository by removing all collaborator students, unassigning the repository from the TA team that * was responsible for it, and archiving it. * @param studentTeam The student team for which to archive. - * @throws IOException + * @throws IOException If an io exception occurred, duh! */ public void deactivateRepository(StudentTeam studentTeam) throws IOException { GHOrganization organization = this.github.getOrganization(studentTeam.getCourse().getGithubOrganizationName()); diff --git a/src/main/resources/templates/courses/entity/student_teams.html b/src/main/resources/templates/courses/entity/student_teams.html index 6bb8dc3..04c6daf 100644 --- a/src/main/resources/templates/courses/entity/student_teams.html +++ b/src/main/resources/templates/courses/entity/student_teams.html @@ -69,6 +69,9 @@ + From 035a7f9c443f4a1a29c4e1ecfcb09bc7fd8bd5b4 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Fri, 10 May 2019 13:13:41 +0200 Subject: [PATCH 8/8] Cleaned up the courses list and added some more metrics. --- .../student_teams/MergeSingleTeams.java | 4 +++ .../model/Course.java | 15 +++++++++ src/main/resources/templates/courses.html | 33 ++++++++++--------- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java index e7980e4..1d5ac35 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/controllers/courses/entity/student_teams/MergeSingleTeams.java @@ -15,6 +15,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +/** + * Controller for the action to merge all single teams in a course. + * TODO: Implement this functionality automatically. + */ @Controller public class MergeSingleTeams { diff --git a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java index e22cf53..d1dfe0b 100644 --- a/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java +++ b/src/main/java/nl/andrewlalis/teaching_assistant_assistant/model/Course.java @@ -6,6 +6,7 @@ import nl.andrewlalis.teaching_assistant_assistant.model.people.Student; import nl.andrewlalis.teaching_assistant_assistant.model.people.TeachingAssistant; import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam; import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.TeachingAssistantTeam; +import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.Team; import javax.persistence.*; import java.util.ArrayList; @@ -205,4 +206,18 @@ public class Course extends BasicEntity { } return sb.toString(); } + + public int getNumberOfStudentsInTeams() { + int sum = 0; + for (Student s : this.getStudents()) { + for (Team team : s.getTeams()) { + if (team.getCourse().equals(this)) { + sum++; + break; + } + } + } + + return sum; + } } diff --git a/src/main/resources/templates/courses.html b/src/main/resources/templates/courses.html index 42b41e7..a225f7a 100644 --- a/src/main/resources/templates/courses.html +++ b/src/main/resources/templates/courses.html @@ -6,22 +6,23 @@
    - - - - - - - - - - - - - -
    NameCodeCreated atStudents
    - -
    +

    Courses

    +
    + +
      +
    • +

      +
        +
      • Code:
      • +
      • Created on:
      • +
      • Students:
      • +
      • Teaching Assistants:
      • +
      • Student Teams:
      • +
      • Teaching Assistant Teams:
      • +
      • Number of Active Students (in a team):
      • +
      +
    • +