Did more than can be explained in a commit message.
This commit is contained in:
parent
5670e25a40
commit
64f75ea21d
|
@ -1,17 +1,29 @@
|
||||||
package nl.andrewlalis.teaching_assistant_assistant.controllers;
|
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 nl.andrewlalis.teaching_assistant_assistant.model.repositories.StudentRepository;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
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
|
@Controller
|
||||||
public class Students {
|
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.studentRepository = studentRepository;
|
||||||
|
this.courseRepository = courseRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/students")
|
@GetMapping("/students")
|
||||||
|
@ -19,4 +31,35 @@ public class Students {
|
||||||
model.addAttribute("students", this.studentRepository.findAll());
|
model.addAttribute("students", this.studentRepository.findAll());
|
||||||
return "students";
|
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<Course> 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,42 @@
|
||||||
package nl.andrewlalis.teaching_assistant_assistant.controllers.courses.entity.student_teams;
|
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.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.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.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
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;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class StudentTeamEntity {
|
public class StudentTeamEntity {
|
||||||
|
|
||||||
private StudentTeamRepository studentTeamRepository;
|
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.studentTeamRepository = studentTeamRepository;
|
||||||
|
this.courseRepository = courseRepository;
|
||||||
|
this.studentRepository = studentRepository;
|
||||||
|
this.teachingAssistantTeamRepository = teachingAssistantTeamRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,4 +53,230 @@ public class StudentTeamEntity {
|
||||||
|
|
||||||
return "courses/entity/student_teams/entity";
|
return "courses/entity/student_teams/entity";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/courses/{courseCode}/student_teams/create")
|
||||||
|
public String getCreate(@PathVariable String courseCode, Model model) {
|
||||||
|
Optional<Course> 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<Course> 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<Course> optionalCourse = this.courseRepository.findByCode(courseCode);
|
||||||
|
Optional<StudentTeam> 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<Course> optionalCourse = this.courseRepository.findByCode(courseCode);
|
||||||
|
Optional<StudentTeam> optionalStudentTeam = this.studentTeamRepository.findById(teamId);
|
||||||
|
Optional<Student> 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<Course> optionalCourse = this.courseRepository.findByCode(courseCode);
|
||||||
|
Optional<StudentTeam> 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<Course> optionalCourse = this.courseRepository.findByCode(courseCode);
|
||||||
|
Optional<StudentTeam> optionalStudentTeam = this.studentTeamRepository.findById(teamId);
|
||||||
|
Optional<TeachingAssistantTeam> 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<Course> optionalCourse = this.courseRepository.findByCode(courseCode);
|
||||||
|
Optional<StudentTeam> optionalStudentTeam = this.studentTeamRepository.findById(teamId);
|
||||||
|
Optional<Student> 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<Course> optionalCourse = this.courseRepository.findByCode(courseCode);
|
||||||
|
Optional<StudentTeam> 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<Course> optionalCourse = this.courseRepository.findByCode(courseCode);
|
||||||
|
Optional<StudentTeam> 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,6 @@ public class InviteAllToRepository {
|
||||||
keys.add(rawKey.trim());
|
keys.add(rawKey.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
String fullRepositoryName = course.getGithubOrganizationName() + '/' + repositoryName;
|
|
||||||
|
|
||||||
int inviteCounter = 0;
|
int inviteCounter = 0;
|
||||||
GithubManager manager;
|
GithubManager manager;
|
||||||
try {
|
try {
|
||||||
|
@ -80,24 +78,30 @@ public class InviteAllToRepository {
|
||||||
if (inviteCounter == 50) {
|
if (inviteCounter == 50) {
|
||||||
System.out.println("Used up 50 invites on key.");
|
System.out.println("Used up 50 invites on key.");
|
||||||
try {
|
try {
|
||||||
|
if (keys.isEmpty()) {
|
||||||
|
System.err.println("No more keys.");
|
||||||
|
failedNames.addAll(githubUsernames);
|
||||||
|
break;
|
||||||
|
}
|
||||||
manager = new GithubManager(keys.remove(0));
|
manager = new GithubManager(keys.remove(0));
|
||||||
inviteCounter = 0;
|
inviteCounter = 0;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
failedNames.addAll(githubUsernames);
|
failedNames.addAll(githubUsernames);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String username = githubUsernames.remove(0);
|
String username = githubUsernames.remove(0);
|
||||||
try {
|
try {
|
||||||
manager.addCollaborator(fullRepositoryName, username, "pull");
|
manager.addCollaborator(course.getGithubOrganizationName(), repositoryName, username, "pull");
|
||||||
inviteCounter++;
|
inviteCounter++;
|
||||||
System.out.println("\tInvited " + username);
|
System.out.println("\tInvited " + username);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
//e.printStackTrace();
|
//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);
|
failedNames.add(username);
|
||||||
|
inviteCounter = 50; // Try to use a different key if possible.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package nl.andrewlalis.teaching_assistant_assistant.controllers.students;
|
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.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.StudentRepository;
|
||||||
|
import nl.andrewlalis.teaching_assistant_assistant.model.repositories.TeamRepository;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
@ -15,9 +19,13 @@ import java.util.Optional;
|
||||||
public class StudentEntity {
|
public class StudentEntity {
|
||||||
|
|
||||||
private StudentRepository studentRepository;
|
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.studentRepository = studentRepository;
|
||||||
|
this.teamRepository = teamRepository;
|
||||||
|
this.courseRepository = courseRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/students/{id}")
|
@GetMapping("/students/{id}")
|
||||||
|
@ -51,4 +59,27 @@ public class StudentEntity {
|
||||||
|
|
||||||
return "redirect:/students/{id}";
|
return "redirect:/students/{id}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/students/{id}/remove")
|
||||||
|
public String getRemove(@PathVariable long id) {
|
||||||
|
Optional<Student> 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,10 @@ public class Course extends BasicEntity {
|
||||||
this.studentTeams.add(team);
|
this.studentTeams.add(team);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeStudentTeam(StudentTeam team) {
|
||||||
|
this.studentTeams.remove(team);
|
||||||
|
}
|
||||||
|
|
||||||
public void addTeachingAssistantTeam(TeachingAssistantTeam team) {
|
public void addTeachingAssistantTeam(TeachingAssistantTeam team) {
|
||||||
this.teachingAssistantTeams.add(team);
|
this.teachingAssistantTeams.add(team);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,12 +80,20 @@ public abstract class Person extends BasicEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeFromAssignedTeam(Team team) {
|
||||||
|
this.teams.remove(team);
|
||||||
|
}
|
||||||
|
|
||||||
public void assignToCourse(Course course) {
|
public void assignToCourse(Course course) {
|
||||||
if (!this.courses.contains(course)) {
|
if (!this.courses.contains(course)) {
|
||||||
this.courses.add(course);
|
this.courses.add(course);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeFromAssignedCourse(Course course) {
|
||||||
|
this.courses.remove(course);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Getters and Setters
|
Getters and Setters
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,7 +50,17 @@ public class Student extends Person {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
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
|
@Override
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package nl.andrewlalis.teaching_assistant_assistant.model.people.teams;
|
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.assignments.grades.AssignmentGrade;
|
||||||
import nl.andrewlalis.teaching_assistant_assistant.model.people.Person;
|
import nl.andrewlalis.teaching_assistant_assistant.model.people.Person;
|
||||||
import nl.andrewlalis.teaching_assistant_assistant.model.people.Student;
|
import nl.andrewlalis.teaching_assistant_assistant.model.people.Student;
|
||||||
|
@ -41,6 +42,10 @@ public class StudentTeam extends Team {
|
||||||
*/
|
*/
|
||||||
public StudentTeam() {}
|
public StudentTeam() {}
|
||||||
|
|
||||||
|
public StudentTeam(Course course) {
|
||||||
|
super(course);
|
||||||
|
}
|
||||||
|
|
||||||
public List<Student> getStudents() {
|
public List<Student> getStudents() {
|
||||||
List<Person> people = super.getMembers();
|
List<Person> people = super.getMembers();
|
||||||
List<Student> students = new ArrayList<>();
|
List<Student> students = new ArrayList<>();
|
||||||
|
|
|
@ -47,6 +47,15 @@ public abstract class Team extends BasicEntity {
|
||||||
this.members = new ArrayList<>();
|
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) {
|
public void addMember(Person person) {
|
||||||
if (!this.containsMember(person)) {
|
if (!this.containsMember(person)) {
|
||||||
this.members.add(person);
|
this.members.add(person);
|
||||||
|
|
|
@ -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.Student;
|
||||||
import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam;
|
import nl.andrewlalis.teaching_assistant_assistant.model.people.teams.StudentTeam;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPatch;
|
||||||
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpPut;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
@ -15,7 +16,9 @@ import org.kohsuke.github.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,7 +167,7 @@ public class GithubManager {
|
||||||
|
|
||||||
private void addStudentsAsCollaborators(GHRepository repository, StudentTeam studentTeam) throws IOException {
|
private void addStudentsAsCollaborators(GHRepository repository, StudentTeam studentTeam) throws IOException {
|
||||||
for (Student student : studentTeam.getStudents()) {
|
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);
|
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 {
|
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);
|
HttpPut put = new HttpPut(url);
|
||||||
CloseableHttpClient client = HttpClientBuilder.create().build();
|
CloseableHttpClient client = HttpClientBuilder.create().build();
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
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<GHUser> 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 {
|
private void addRepositoryToTeam(GHTeam team, GHRepository repository) throws IOException {
|
||||||
team.add(repository, GHOrganization.Permission.ADMIN);
|
team.add(repository, GHOrganization.Permission.ADMIN);
|
||||||
}
|
}
|
||||||
|
@ -222,4 +255,23 @@ public class GithubManager {
|
||||||
builder.enable();
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="sidebar">
|
<div id="sidebar">
|
||||||
<div class="sidebar_block">
|
|
||||||
block
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -66,6 +66,9 @@
|
||||||
<div class="sidebar_block">
|
<div class="sidebar_block">
|
||||||
<a th:href="@{/courses/{code}/student_teams/export_contact_info(code=${course.getCode()})}">Export Team Contact Details</a>
|
<a th:href="@{/courses/{code}/student_teams/export_contact_info(code=${course.getCode()})}">Export Team Contact Details</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sidebar_block">
|
||||||
|
<a th:href="@{/courses/{code}/student_teams/create(code=${course.getCode()})}">Create New Student Team</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
|
||||||
|
<head>
|
||||||
|
<title>Create Student Team</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<h1>Create a New Student Team</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Creates a new student team for the <span th:text="${course.getName()}"></span> course, without any assigned TA team or student members.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form action="#" th:action="@{/courses/{code}/student_teams/create(code=${course.getCode()})}" enctype="application/x-www-form-urlencoded" method="post">
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="sidebar">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -16,7 +16,7 @@
|
||||||
<span th:text="${student_team.getGithubRepositoryName()}"></span>
|
<span th:text="${student_team.getGithubRepositoryName()}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li th:if="${student_team.getAssignedTeachingAssistantTeam() != null}">
|
||||||
Assigned Teaching Assistant Team:
|
Assigned Teaching Assistant Team:
|
||||||
<a
|
<a
|
||||||
th:if="${student_team.getAssignedTeachingAssistantTeam() != null}"
|
th:if="${student_team.getAssignedTeachingAssistantTeam() != null}"
|
||||||
|
@ -31,6 +31,10 @@
|
||||||
<a th:href="@{/students/{id}(id=${student.getId()})}">
|
<a th:href="@{/students/{id}(id=${student.getId()})}">
|
||||||
<span th:text="${student.getFullName()}"></span>
|
<span th:text="${student.getFullName()}"></span>
|
||||||
</a>
|
</a>
|
||||||
|
(<a
|
||||||
|
th:href="@{/courses/{code}/student_teams/{id}/remove_student/{student_id}
|
||||||
|
(code=${student_team.getCourse().getCode()}, id=${student_team.getId()}, student_id=${student.getId()})}"
|
||||||
|
>Remove From This Team</a>)
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
@ -39,17 +43,37 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="sidebar">
|
<div id="sidebar">
|
||||||
<div class="sidebar_block">
|
<div class="sidebar_block" th:if="${student_team.getGithubRepositoryName() == null && student_team.getAssignedTeachingAssistantTeam() != null}">
|
||||||
<a
|
<a
|
||||||
th:if="${student_team.getGithubRepositoryName() == null}"
|
|
||||||
th:href="@{/courses/{code}/student_teams/{id}/generate_repository
|
th:href="@{/courses/{code}/student_teams/{id}/generate_repository
|
||||||
(code=${student_team.getCourse().getCode()}, id=${student_team.getAssignedTeachingAssistantTeam().getId()})}"
|
(code=${student_team.getCourse().getCode()}, id=${student_team.getId()})}"
|
||||||
>Generate Repository</a>
|
>Generate Repository</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar_block" th:if="${student_team.getGithubRepositoryName() != null}">
|
||||||
<a
|
<a
|
||||||
th:if="${student_team.getGithubRepositoryName() != null}"
|
|
||||||
th:href="@{/courses/{code}/student_teams/{id}/delete_repository
|
th:href="@{/courses/{code}/student_teams/{id}/delete_repository
|
||||||
(code=${student_team.getCourse().getCode()}, id=${student_team.getAssignedTeachingAssistantTeam().getId()})}"
|
(code=${student_team.getCourse().getCode()}, id=${student_team.getAssignedTeachingAssistantTeam().getId()})}"
|
||||||
>Delete Repository</a>
|
>Archive Repository</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar_block">
|
||||||
|
<a th:href="@{/courses/{code}/student_teams/{id}/add_student(code=${student_team.getCourse().getCode()}, id=${student_team.getId()})}">
|
||||||
|
Add Student To Team
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar_block">
|
||||||
|
<a th:href="@{/courses/{code}/student_teams/{id}/assign_teaching_assistant_team(code=${student_team.getCourse().getCode()}, id=${student_team.getId()})}">
|
||||||
|
Assign Teaching Assistant Team
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar_block">
|
||||||
|
<a th:href="@{/courses/{code}/student_teams/{id}/remove(code=${student_team.getCourse().getCode()}, id=${student_team.getId()})}">Remove This Team</a>
|
||||||
|
<p>
|
||||||
|
Removes this team permanently, and archives the repository.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
|
||||||
|
<head>
|
||||||
|
<title>Add Student To Team</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<h1>Add a Student to Team <span th:text="${student_team.getId()}"></span></h1>
|
||||||
|
|
||||||
|
<form
|
||||||
|
action="#"
|
||||||
|
th:action="@{/courses/{code}/student_teams/{id}/add_student(code=${course.getCode()}, id=${student_team.getId()})}"
|
||||||
|
enctype="application/x-www-form-urlencoded"
|
||||||
|
method="post"
|
||||||
|
>
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="student_select">Select a Student to Add:</label>
|
||||||
|
<select id="student_select" name="student_id" required>
|
||||||
|
<option th:each="student: ${eligible_students}" th:value="${student.getId()}" th:text="${student.getFullName()}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="sidebar">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
|
||||||
|
<head>
|
||||||
|
<title>Assign Teaching Assistant Team</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<h1>Assign a Teaching Assistant Team to Student Team <span th:text="${student_team.getId()}"></span></h1>
|
||||||
|
|
||||||
|
<form
|
||||||
|
action="#"
|
||||||
|
th:action="@{/courses/{code}/student_teams/{id}/assign_teaching_assistant_team(code=${course.getCode()}, id=${student_team.getId()})}"
|
||||||
|
enctype="application/x-www-form-urlencoded"
|
||||||
|
method="post"
|
||||||
|
>
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="ta_team_select">Select a Team:</label>
|
||||||
|
<select id="ta_team_select" name="teaching_assistant_team_id">
|
||||||
|
<option value="-1">None</option>
|
||||||
|
<option
|
||||||
|
th:each="team: ${course.getTeachingAssistantTeams()}" th:value="${team.getId()}"
|
||||||
|
th:text="${'Team ' + team.getId() + ' (Manages ' + team.getAssignedStudentTeams().size() + ' student teams)'}"
|
||||||
|
></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="sidebar">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -6,17 +6,17 @@
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<footer th:fragment="footer" class="footer_bar">
|
<footer th:fragment="footer" class="footer_bar">
|
||||||
<link rel="stylesheet" href="../../../resources/static/css/footer.css" th:href="@{/css/footer.css}"/>
|
<!-- <link rel="stylesheet" href="../../../resources/static/css/footer.css" th:href="@{/css/footer.css}"/>-->
|
||||||
|
|
||||||
<div class="third">
|
<!-- <div class="third">-->
|
||||||
First third of footer
|
<!-- First third of footer-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="third">
|
<!-- <div class="third">-->
|
||||||
Middle of footer
|
<!-- Middle of footer-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="third">
|
<!-- <div class="third">-->
|
||||||
Right side of footer.
|
<!-- Right side of footer.-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,17 @@
|
||||||
></a>
|
></a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<a th:href="@{/students/{id}/remove(id=${student.getId()})}">Remove</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="sidebar">
|
<div id="sidebar">
|
||||||
|
<div class="sidebar_block">
|
||||||
|
<a th:href="@{/students/create}">Create Student</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
|
||||||
|
<head>
|
||||||
|
<title>Create a Student</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<h1>Create New Student</h1>
|
||||||
|
|
||||||
|
<form action="#" th:action="@{/students/create}" th:object="${student}" method="post" enctype="application/x-www-form-urlencoded">
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="student_first_name_input">First Name:</label>
|
||||||
|
<input id="student_first_name_input" type="text" th:field="*{firstName}" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="student_last_name_input">Last Name:</label>
|
||||||
|
<input id="student_last_name_input" type="text" th:field="*{lastName}" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="student_email_input">Email Address:</label>
|
||||||
|
<input id="student_email_input" type="email" th:field="*{emailAddress}" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="student_github_username_input">Github Username:</label>
|
||||||
|
<input id="student_github_username_input" type="text" th:field="*{githubUsername}" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="student_number_input">Student Number:</label>
|
||||||
|
<input id="student_number_input" type="number" th:field="*{studentNumber}" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<label for="student_course_select">Select a course to add the student to:</label>
|
||||||
|
<select id="student_course_select" name="course_code">
|
||||||
|
<option value="NO_COURSE_SELECTED">None</option>
|
||||||
|
<option
|
||||||
|
th:each="course: ${courses}"
|
||||||
|
th:value="${course.getCode()}"
|
||||||
|
th:text="${course.getName()}"
|
||||||
|
></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_row">
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="sidebar">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue